Skip to content
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

Ignore global variables prefixed with //go:embed #22

Merged
merged 12 commits into from
Oct 27, 2021
Merged
41 changes: 37 additions & 4 deletions checknoglobals/check_no_globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ func flags() flag.FlagSet {
return *flags
}

func isAllowed(v ast.Node) bool {
func isAllowed(cm ast.CommentMap, v ast.Node) bool {
switch i := v.(type) {
case *ast.GenDecl:
return hasEmbedComment(cm, i)
case *ast.Ident:
return i.Name == "_" || i.Name == "version" || looksLikeError(i)
return i.Name == "_" || i.Name == "version" || looksLikeError(i) || identHasEmbedComment(cm, i)
case *ast.CallExpr:
if expr, ok := i.Fun.(*ast.SelectorExpr); ok {
return isAllowedSelectorExpression(expr)
Expand Down Expand Up @@ -96,6 +98,32 @@ func looksLikeError(i *ast.Ident) bool {
return strings.HasPrefix(i.Name, prefix)
}

func identHasEmbedComment(cm ast.CommentMap, i *ast.Ident) bool {
if i.Obj == nil {
return false
}

spec, ok := i.Obj.Decl.(*ast.ValueSpec)
if !ok {
return false
}

return hasEmbedComment(cm, spec)
}

// hasEmbedComment returns true if the AST node has
// a '//go:embed ' comment, or false otherwise.
func hasEmbedComment(cm ast.CommentMap, n ast.Node) bool {
for _, g := range cm[n] {
for _, c := range g.List {
if strings.HasPrefix(c.Text, "//go:embed ") {
return true
}
}
}
return false
}

func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
includeTests := pass.Analyzer.Flags.Lookup("t").Value.(flag.Getter).Get().(bool)

Expand All @@ -108,6 +136,8 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
continue
}

fileCommentMap := ast.NewCommentMap(pass.Fset, file, file.Comments)

for _, decl := range file.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
Expand All @@ -116,12 +146,15 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
if genDecl.Tok != token.VAR {
continue
}
if isAllowed(fileCommentMap, genDecl) {
continue
}
for _, spec := range genDecl.Specs {
valueSpec := spec.(*ast.ValueSpec)
onlyAllowedValues := false

for _, vn := range valueSpec.Values {
if isAllowed(vn) {
if isAllowed(fileCommentMap, vn) {
onlyAllowedValues = true
continue
}
Expand All @@ -135,7 +168,7 @@ func checkNoGlobals(pass *analysis.Pass) (interface{}, error) {
}

for _, vn := range valueSpec.Names {
if isAllowed(vn) {
if isAllowed(fileCommentMap, vn) {
continue
}

Expand Down
2 changes: 1 addition & 1 deletion checknoglobals/check_no_globals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestCheckNoGlobals(t *testing.T) {
analyzer := Analyzer()
analyzer.Flags = *flags

for i := 0; i <= 10; i++ {
for i := 0; i <= 11; i++ {
dir := strconv.Itoa(i)
t.Run(dir, func(t *testing.T) {
analysistest.Run(t, testdata, analyzer, dir)
Expand Down
93 changes: 93 additions & 0 deletions checknoglobals/testdata/src/11/code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package code

import (
"embed"
)

//go:embed embedfiles/*
var fileSystem embed.FS

//go:embed embedfiles/embedfile.txt
var str string

//go:embed embedfiles/embedfile.txt
var data []byte

//go:embed embedfiles/embedfile.txt
//
var strExtraCommentLines string

//go:embed embedfiles/embedfile.txt

var strEmptyLines string

var strEmptyLinesNoComment string // want "strEmptyLinesNoComment is a global variable"

// go : embed that does not match
var strEmptyLinesOtherComment string // want "strEmptyLinesOtherComment is a global variable"

//go:embed embedfiles/embedfile.txt
//

var strExtraCommentLinesAndEmptyLines string

/*
This is a long comment
Spanning over multiple lines
*/
//go:embed embedfiles/embedfile.txt
var strLongCommentAbove string

//go:embed embedfiles/embedfile.txt
/*
This is a long comment
Spanning over multiple lines
*/
var strLongCommentBelow string

/*
This is a long comment
Spanning over multiple lines
*/
//go:embed embedfiles/embedfile.txt
/*
This is a long comment
Spanning over multiple lines
*/
var strLongCommentSurround string

/*
This is a long comment
Spanning over multiple lines
*/

//go:embed embedfiles/embedfile.txt

/*
This is a long comment
Spanning over multiple lines
*/

var strLongCommentSurroundEmptyLines string

var (
//go:embed embedfiles/embedfile.txt
groupedStr string

//go:embed embedfiles/embedfile.txt
groupedData []byte

//go:embed embedfiles/embedfile.txt

groupedStrEmptyLines string

groupedStrEmptyLinesNoComment string // want "groupedStrEmptyLinesNoComment is a global variable"

// go : embed that does not match
groupedStrEmptyLinesOtherComment string // want "groupedStrEmptyLinesOtherComment is a global variable"

//go:embed embedfiles/embedfile.txt
//

groupedStrExtraCommentLinesAndEmptyLines string
)
Empty file.