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

Update gochecknoglobals, use source analyzer #1422

Merged
merged 9 commits into from Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Expand Up @@ -3,6 +3,7 @@ module github.com/golangci/golangci-lint
go 1.12

require (
4d63.com/gochecknoglobals v0.0.0-20201008074935-acfc0b28355a
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5
github.com/OpenPeeDeeP/depguard v1.0.1
github.com/bombsimon/wsl/v3 v3.1.0
Expand Down Expand Up @@ -61,7 +62,7 @@ require (
github.com/ultraware/whitespace v0.0.4
github.com/uudashr/gocognit v1.0.1
github.com/valyala/quicktemplate v1.6.3
golang.org/x/tools v0.0.0-20200918232735-d647fc253266
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d
gopkg.in/yaml.v2 v2.3.0
honnef.co/go/tools v0.0.1-2020.1.5
mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d
Expand Down
6 changes: 4 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 15 additions & 85 deletions pkg/golinters/gochecknoglobals.go
@@ -1,100 +1,30 @@
package golinters

import (
"fmt"
"go/ast"
"go/token"
"strings"
"sync"
"flag"

"golang.org/x/tools/go/analysis"

"4d63.com/gochecknoglobals/checknoglobals"

"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
)

const gochecknoglobalsName = "gochecknoglobals"

//nolint:dupl
func NewGochecknoglobals() *goanalysis.Linter {
var mu sync.Mutex
var resIssues []goanalysis.Issue

analyzer := &analysis.Analyzer{
Name: gochecknoglobalsName,
Doc: goanalysis.TheOnlyanalyzerDoc,
Run: func(pass *analysis.Pass) (interface{}, error) {
var res []goanalysis.Issue
for _, file := range pass.Files {
fileIssues := checkFileForGlobals(file, pass.Fset)
for i := range fileIssues {
res = append(res, goanalysis.NewIssue(&fileIssues[i], pass))
}
}
if len(res) == 0 {
return nil, nil
}
// gochecknoglobals only lints test files if the `-t` flag is passed so we
// set up our own FlagSet and add it to the analyzer before running it. This
// can be turned of by using the regular golangci-lint flags such as
// `--tests` or `--skip-files`.
flags := flag.NewFlagSet("", flag.ContinueOnError)
bombsimon marked this conversation as resolved.
Show resolved Hide resolved
flags.Bool("t", true, "Include tests")
bombsimon marked this conversation as resolved.
Show resolved Hide resolved

mu.Lock()
resIssues = append(resIssues, res...)
mu.Unlock()
gochecknoglobals := checknoglobals.Analyzer()
gochecknoglobals.Flags = *flags

return nil, nil
},
}
return goanalysis.NewLinter(
gochecknoglobalsName,
"Checks that no globals are present in Go code",
[]*analysis.Analyzer{analyzer},
gochecknoglobals.Name,
gochecknoglobals.Doc,
[]*analysis.Analyzer{gochecknoglobals},
nil,
bombsimon marked this conversation as resolved.
Show resolved Hide resolved
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
return resIssues
}).WithLoadMode(goanalysis.LoadModeSyntax)
}

func checkFileForGlobals(f *ast.File, fset *token.FileSet) []result.Issue {
var res []result.Issue
for _, decl := range f.Decls {
genDecl, ok := decl.(*ast.GenDecl)
if !ok {
continue
}
if genDecl.Tok != token.VAR {
continue
}

for _, spec := range genDecl.Specs {
valueSpec := spec.(*ast.ValueSpec)
for _, vn := range valueSpec.Names {
if isWhitelisted(vn) {
continue
}

res = append(res, result.Issue{
Pos: fset.Position(vn.Pos()),
Text: fmt.Sprintf("%s is a global variable", formatCode(vn.Name, nil)),
FromLinter: gochecknoglobalsName,
})
}
}
}

return res
}

func isWhitelisted(i *ast.Ident) bool {
return i.Name == "_" || i.Name == "version" || looksLikeError(i)
}

// looksLikeError returns true if the AST identifier starts
// with 'err' or 'Err', or false otherwise.
//
// TODO: https://github.com/leighmcculloch/gochecknoglobals/issues/5
func looksLikeError(i *ast.Ident) bool {
prefix := "err"
if i.IsExported() {
prefix = "Err"
}
return strings.HasPrefix(i.Name, prefix)
).WithLoadMode(goanalysis.LoadModeSyntax)
}
1 change: 0 additions & 1 deletion pkg/golinters/gochecknoinits.go
Expand Up @@ -15,7 +15,6 @@ import (

const gochecknoinitsName = "gochecknoinits"

//nolint:dupl
func NewGochecknoinits() *goanalysis.Linter {
var mu sync.Mutex
var resIssues []goanalysis.Issue
Expand Down
8 changes: 7 additions & 1 deletion test/testdata/gochecknoglobals.go
Expand Up @@ -4,11 +4,17 @@ package testdata
import (
"errors"
"fmt"
"regexp"
)

var noGlobalsVar int // ERROR "`noGlobalsVar` is a global variable"
var noGlobalsVar int // ERROR "noGlobalsVar is a global variable"
var ErrSomeType = errors.New("test that global erorrs aren't warned")

var (
OnlyDigites = regexp.MustCompile(`^\d+$`)
BadNamedErr = errors.New("this is bad") // ERROR "BadNamedErr is a global variable"
)

func NoGlobals() {
fmt.Print(noGlobalsVar)
}
6 changes: 0 additions & 6 deletions test/testdata/testpackage_internal_test.go

This file was deleted.