initial vendor commit
This commit is contained in:
1 parent
747c805a82
commit
21e1fb3451
660 files changed
+133146
No files matched your search
@@ -0,0 +1,7 @@
|
||||
language: go
|
||||
|
||||
install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
@@ -0,0 +1,15 @@
|
||||
# Contributing to Golint
|
||||
|
||||
## Before filing an issue:
|
||||
|
||||
### Are you having trouble building golint?
|
||||
|
||||
Check you have the latest version of its dependencies. Run
|
||||
```
|
||||
go get -u github.com/golang/lint
|
||||
```
|
||||
If you still have problems, consider searching for existing issues before filing a new issue.
|
||||
|
||||
## Before sending a pull request:
|
||||
|
||||
Have you understood the purpose of golint? Make sure to carefully read `README`.
|
||||
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2013 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,67 @@
|
||||
Golint is a linter for Go source code.
|
||||
|
||||
[](https://travis-ci.org/golang/lint)
|
||||
|
||||
To install, run
|
||||
go get -u github.com/golang/lint/golint
|
||||
|
||||
Invoke golint with one or more filenames, a directory, or a package named
|
||||
by its import path. Golint uses the same import path syntax as the go
|
||||
command (https://golang.org/cmd/go/#hdr-Import_path_syntax) and therefore
|
||||
also supports relative import paths like "./...". Additionally the "..."
|
||||
wildcard can be used as suffix on relative and absolute file paths to recurse
|
||||
into them.
|
||||
|
||||
The output of this tool is a list of suggestions in Vim quickfix format,
|
||||
which is accepted by lots of different editors.
|
||||
|
||||
Golint differs from gofmt. Gofmt reformats Go source code, whereas
|
||||
golint prints out style mistakes.
|
||||
|
||||
Golint differs from govet. Govet is concerned with correctness, whereas
|
||||
golint is concerned with coding style. Golint is in use at Google, and it
|
||||
seeks to match the accepted style of the open source Go project.
|
||||
|
||||
The suggestions made by golint are exactly that: suggestions.
|
||||
Golint is not perfect, and has both false positives and false negatives.
|
||||
Do not treat its output as a gold standard. We will not be adding pragmas
|
||||
or other knobs to suppress specific warnings, so do not expect or require
|
||||
code to be completely "lint-free".
|
||||
In short, this tool is not, and will never be, trustworthy enough for its
|
||||
suggestions to be enforced automatically, for example as part of a build process.
|
||||
|
||||
If you find an established style that is frequently violated, and which
|
||||
you think golint could statically check, file an issue at
|
||||
https://github.com/golang/lint/issues
|
||||
|
||||
|
||||
Contributions
|
||||
-------------
|
||||
Contributions to this project are welcome, though please send mail before
|
||||
starting work on anything major. Contributors retain their copyright, so we
|
||||
need you to fill out a short form before we can accept your contribution:
|
||||
https://developers.google.com/open-source/cla/individual
|
||||
|
||||
|
||||
Vim
|
||||
---
|
||||
Add this to your ~/.vimrc:
|
||||
set rtp+=$GOPATH/src/github.com/golang/lint/misc/vim
|
||||
If you have multiple entries in your GOPATH, replace $GOPATH with the right value.
|
||||
|
||||
Running :Lint will run golint on the current file and populate the quickfix list.
|
||||
|
||||
Optionally, add this to your ~/.vimrc to automatically run golint on :w
|
||||
autocmd BufWritePost,FileWritePost *.go execute 'Lint' | cwindow
|
||||
|
||||
|
||||
Emacs
|
||||
-----
|
||||
Add this to your .emacs file:
|
||||
(add-to-list 'load-path (concat (getenv "GOPATH") "/src/github.com/golang/lint/misc/emacs"))
|
||||
(require 'golint)
|
||||
If you have multiple entries in your GOPATH, replace $GOPATH with the right value.
|
||||
|
||||
Running M-x golint will run golint on the current file.
|
||||
For more usage, see Compilation-Mode:
|
||||
http://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2013 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
// golint lints the Go source files named on its command line.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/lint"
|
||||
)
|
||||
|
||||
var minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it")
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n")
|
||||
fmt.Fprintf(os.Stderr, "\tgolint [flags] package\n")
|
||||
fmt.Fprintf(os.Stderr, "\tgolint [flags] directory\n")
|
||||
fmt.Fprintf(os.Stderr, "\tgolint [flags] files... # must be a single package\n")
|
||||
fmt.Fprintf(os.Stderr, "Flags:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
switch flag.NArg() {
|
||||
case 0:
|
||||
lintDir(".")
|
||||
case 1:
|
||||
arg := flag.Arg(0)
|
||||
if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-4]) {
|
||||
for _, dirname := range allPackagesInFS(arg) {
|
||||
lintDir(dirname)
|
||||
}
|
||||
} else if isDir(arg) {
|
||||
lintDir(arg)
|
||||
} else if exists(arg) {
|
||||
lintFiles(arg)
|
||||
} else {
|
||||
for _, pkgname := range importPaths([]string{arg}) {
|
||||
lintPackage(pkgname)
|
||||
}
|
||||
}
|
||||
default:
|
||||
lintFiles(flag.Args()...)
|
||||
}
|
||||
}
|
||||
|
||||
func isDir(filename string) bool {
|
||||
fi, err := os.Stat(filename)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
func exists(filename string) bool {
|
||||
_, err := os.Stat(filename)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func lintFiles(filenames ...string) {
|
||||
files := make(map[string][]byte)
|
||||
for _, filename := range filenames {
|
||||
src, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
continue
|
||||
}
|
||||
files[filename] = src
|
||||
}
|
||||
|
||||
l := new(lint.Linter)
|
||||
ps, err := l.LintFiles(files)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return
|
||||
}
|
||||
for _, p := range ps {
|
||||
if p.Confidence >= *minConfidence {
|
||||
fmt.Printf("%v: %s\n", p.Position, p.Text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lintDir(dirname string) {
|
||||
pkg, err := build.ImportDir(dirname, 0)
|
||||
lintImportedPackage(pkg, err)
|
||||
}
|
||||
|
||||
func lintPackage(pkgname string) {
|
||||
pkg, err := build.Import(pkgname, ".", 0)
|
||||
lintImportedPackage(pkg, err)
|
||||
}
|
||||
|
||||
func lintImportedPackage(pkg *build.Package, err error) {
|
||||
if err != nil {
|
||||
if _, nogo := err.(*build.NoGoError); nogo {
|
||||
// Don't complain if the failure is due to no Go source files.
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
|
||||
var files []string
|
||||
files = append(files, pkg.GoFiles...)
|
||||
files = append(files, pkg.TestGoFiles...)
|
||||
if pkg.Dir != "." {
|
||||
for i, f := range files {
|
||||
files[i] = filepath.Join(pkg.Dir, f)
|
||||
}
|
||||
}
|
||||
// TODO(dsymonds): Do foo_test too (pkg.XTestGoFiles)
|
||||
|
||||
lintFiles(files...)
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
|
||||
This file holds a direct copy of the import path matching code of
|
||||
https://code.google.com/p/go/source/browse/src/cmd/go/main.go. It can be
|
||||
replaced when https://code.google.com/p/go/issues/detail?id=8768 is resolved.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var buildContext = build.Default
|
||||
|
||||
var (
|
||||
goroot = filepath.Clean(runtime.GOROOT())
|
||||
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
|
||||
)
|
||||
|
||||
// importPathsNoDotExpansion returns the import paths to use for the given
|
||||
// command line, but it does no ... expansion.
|
||||
func importPathsNoDotExpansion(args []string) []string {
|
||||
if len(args) == 0 {
|
||||
return []string{"."}
|
||||
}
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
// Arguments are supposed to be import paths, but
|
||||
// as a courtesy to Windows developers, rewrite \ to /
|
||||
// in command-line arguments. Handles .\... and so on.
|
||||
if filepath.Separator == '\\' {
|
||||
a = strings.Replace(a, `\`, `/`, -1)
|
||||
}
|
||||
|
||||
// Put argument in canonical form, but preserve leading ./.
|
||||
if strings.HasPrefix(a, "./") {
|
||||
a = "./" + path.Clean(a)
|
||||
if a == "./." {
|
||||
a = "."
|
||||
}
|
||||
} else {
|
||||
a = path.Clean(a)
|
||||
}
|
||||
if a == "all" || a == "std" {
|
||||
out = append(out, allPackages(a)...)
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// importPaths returns the import paths to use for the given command line.
|
||||
func importPaths(args []string) []string {
|
||||
args = importPathsNoDotExpansion(args)
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
if strings.Contains(a, "...") {
|
||||
if build.IsLocalImport(a) {
|
||||
out = append(out, allPackagesInFS(a)...)
|
||||
} else {
|
||||
out = append(out, allPackages(a)...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// matchPattern(pattern)(name) reports whether
|
||||
// name matches pattern. Pattern is a limited glob
|
||||
// pattern in which '...' means 'any string' and there
|
||||
// is no other special syntax.
|
||||
func matchPattern(pattern string) func(name string) bool {
|
||||
re := regexp.QuoteMeta(pattern)
|
||||
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
|
||||
// Special case: foo/... matches foo too.
|
||||
if strings.HasSuffix(re, `/.*`) {
|
||||
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
|
||||
}
|
||||
reg := regexp.MustCompile(`^` + re + `$`)
|
||||
return func(name string) bool {
|
||||
return reg.MatchString(name)
|
||||
}
|
||||
}
|
||||
|
||||
// hasPathPrefix reports whether the path s begins with the
|
||||
// elements in prefix.
|
||||
func hasPathPrefix(s, prefix string) bool {
|
||||
switch {
|
||||
default:
|
||||
return false
|
||||
case len(s) == len(prefix):
|
||||
return s == prefix
|
||||
case len(s) > len(prefix):
|
||||
if prefix != "" && prefix[len(prefix)-1] == '/' {
|
||||
return strings.HasPrefix(s, prefix)
|
||||
}
|
||||
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
|
||||
}
|
||||
}
|
||||
|
||||
// treeCanMatchPattern(pattern)(name) reports whether
|
||||
// name or children of name can possibly match pattern.
|
||||
// Pattern is the same limited glob accepted by matchPattern.
|
||||
func treeCanMatchPattern(pattern string) func(name string) bool {
|
||||
wildCard := false
|
||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||
wildCard = true
|
||||
pattern = pattern[:i]
|
||||
}
|
||||
return func(name string) bool {
|
||||
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
|
||||
wildCard && strings.HasPrefix(name, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
// allPackages returns all the packages that can be found
|
||||
// under the $GOPATH directories and $GOROOT matching pattern.
|
||||
// The pattern is either "all" (all packages), "std" (standard packages)
|
||||
// or a path including "...".
|
||||
func allPackages(pattern string) []string {
|
||||
pkgs := matchPackages(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackages(pattern string) []string {
|
||||
match := func(string) bool { return true }
|
||||
treeCanMatch := func(string) bool { return true }
|
||||
if pattern != "all" && pattern != "std" {
|
||||
match = matchPattern(pattern)
|
||||
treeCanMatch = treeCanMatchPattern(pattern)
|
||||
}
|
||||
|
||||
have := map[string]bool{
|
||||
"builtin": true, // ignore pseudo-package that exists only for documentation
|
||||
}
|
||||
if !buildContext.CgoEnabled {
|
||||
have["runtime/cgo"] = true // ignore during walk
|
||||
}
|
||||
var pkgs []string
|
||||
|
||||
// Commands
|
||||
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
|
||||
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == cmd {
|
||||
return nil
|
||||
}
|
||||
name := path[len(cmd):]
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
// Commands are all in cmd/, not in subdirectories.
|
||||
if strings.Contains(name, string(filepath.Separator)) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
|
||||
name = "cmd/" + name
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, src := range buildContext.SrcDirs() {
|
||||
if pattern == "std" && src != gorootSrcPkg {
|
||||
continue
|
||||
}
|
||||
src = filepath.Clean(src) + string(filepath.Separator)
|
||||
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, and testdata directory trees.
|
||||
_, elem := filepath.Split(path)
|
||||
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := filepath.ToSlash(path[len(src):])
|
||||
if pattern == "std" && strings.Contains(name, ".") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); noGo {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// allPackagesInFS is like allPackages but is passed a pattern
|
||||
// beginning ./ or ../, meaning it should scan the tree rooted
|
||||
// at the given directory. There are ... in the pattern too.
|
||||
func allPackagesInFS(pattern string) []string {
|
||||
pkgs := matchPackagesInFS(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackagesInFS(pattern string) []string {
|
||||
// Find directory to begin the scan.
|
||||
// Could be smarter but this one optimization
|
||||
// is enough for now, since ... is usually at the
|
||||
// end of a path.
|
||||
i := strings.Index(pattern, "...")
|
||||
dir, _ := path.Split(pattern[:i])
|
||||
|
||||
// pattern begins with ./ or ../.
|
||||
// path.Clean will discard the ./ but not the ../.
|
||||
// We need to preserve the ./ for pattern matching
|
||||
// and in the returned import paths.
|
||||
prefix := ""
|
||||
if strings.HasPrefix(pattern, "./") {
|
||||
prefix = "./"
|
||||
}
|
||||
match := matchPattern(pattern)
|
||||
|
||||
var pkgs []string
|
||||
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if path == dir {
|
||||
// filepath.Walk starts at dir and recurses. For the recursive case,
|
||||
// the path is the result of filepath.Join, which calls filepath.Clean.
|
||||
// The initial case is not Cleaned, though, so we do this explicitly.
|
||||
//
|
||||
// This converts a path like "./io/" to "io". Without this step, running
|
||||
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
|
||||
// package, because prepending the prefix "./" to the unclean path would
|
||||
// result in "././io", and match("././io") returns false.
|
||||
path = filepath.Clean(path)
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
|
||||
_, elem := filepath.Split(path)
|
||||
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
|
||||
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := prefix + filepath.ToSlash(path)
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
if _, err = build.ImportDir(path, 0); err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
return pkgs
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,262 @@
|
||||
// Copyright (c) 2013 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 or at
|
||||
// https://developers.google.com/open-source/licenses/bsd.
|
||||
|
||||
package lint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/types"
|
||||
)
|
||||
|
||||
var lintMatch = flag.String("lint.match", "", "restrict testdata matches to this pattern")
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
l := new(Linter)
|
||||
rx, err := regexp.Compile(*lintMatch)
|
||||
if err != nil {
|
||||
t.Fatalf("Bad -lint.match value %q: %v", *lintMatch, err)
|
||||
}
|
||||
|
||||
baseDir := "testdata"
|
||||
fis, err := ioutil.ReadDir(baseDir)
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.ReadDir: %v", err)
|
||||
}
|
||||
if len(fis) == 0 {
|
||||
t.Fatalf("no files in %v", baseDir)
|
||||
}
|
||||
for _, fi := range fis {
|
||||
if !rx.MatchString(fi.Name()) {
|
||||
continue
|
||||
}
|
||||
//t.Logf("Testing %s", fi.Name())
|
||||
src, err := ioutil.ReadFile(path.Join(baseDir, fi.Name()))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed reading %s: %v", fi.Name(), err)
|
||||
}
|
||||
|
||||
ins := parseInstructions(t, fi.Name(), src)
|
||||
if ins == nil {
|
||||
t.Errorf("Test file %v does not have instructions", fi.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
ps, err := l.Lint(fi.Name(), src)
|
||||
if err != nil {
|
||||
t.Errorf("Linting %s: %v", fi.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, in := range ins {
|
||||
ok := false
|
||||
for i, p := range ps {
|
||||
if p.Position.Line != in.Line {
|
||||
continue
|
||||
}
|
||||
if in.Match.MatchString(p.Text) {
|
||||
// remove this problem from ps
|
||||
copy(ps[i:], ps[i+1:])
|
||||
ps = ps[:len(ps)-1]
|
||||
|
||||
//t.Logf("/%v/ matched at %s:%d", in.Match, fi.Name(), in.Line)
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
t.Errorf("Lint failed at %s:%d; /%v/ did not match", fi.Name(), in.Line, in.Match)
|
||||
}
|
||||
}
|
||||
for _, p := range ps {
|
||||
t.Errorf("Unexpected problem at %s:%d: %v", fi.Name(), p.Position.Line, p.Text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type instruction struct {
|
||||
Line int // the line number this applies to
|
||||
Match *regexp.Regexp // what pattern to match
|
||||
}
|
||||
|
||||
// parseInstructions parses instructions from the comments in a Go source file.
|
||||
// It returns nil if none were parsed.
|
||||
func parseInstructions(t *testing.T, filename string, src []byte) []instruction {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Fatalf("Test file %v does not parse: %v", filename, err)
|
||||
}
|
||||
var ins []instruction
|
||||
for _, cg := range f.Comments {
|
||||
ln := fset.Position(cg.Pos()).Line
|
||||
raw := cg.Text()
|
||||
for _, line := range strings.Split(raw, "\n") {
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if line == "OK" && ins == nil {
|
||||
// so our return value will be non-nil
|
||||
ins = make([]instruction, 0)
|
||||
continue
|
||||
}
|
||||
if strings.Contains(line, "MATCH") {
|
||||
rx, err := extractPattern(line)
|
||||
if err != nil {
|
||||
t.Fatalf("At %v:%d: %v", filename, ln, err)
|
||||
}
|
||||
matchLine := ln
|
||||
if i := strings.Index(line, "MATCH:"); i >= 0 {
|
||||
// This is a match for a different line.
|
||||
lns := strings.TrimPrefix(line[i:], "MATCH:")
|
||||
lns = lns[:strings.Index(lns, " ")]
|
||||
matchLine, err = strconv.Atoi(lns)
|
||||
if err != nil {
|
||||
t.Fatalf("Bad match line number %q at %v:%d: %v", lns, filename, ln, err)
|
||||
}
|
||||
}
|
||||
ins = append(ins, instruction{
|
||||
Line: matchLine,
|
||||
Match: rx,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ins
|
||||
}
|
||||
|
||||
func extractPattern(line string) (*regexp.Regexp, error) {
|
||||
a, b := strings.Index(line, "/"), strings.LastIndex(line, "/")
|
||||
if a == -1 || a == b {
|
||||
return nil, fmt.Errorf("malformed match instruction %q", line)
|
||||
}
|
||||
pat := line[a+1 : b]
|
||||
rx, err := regexp.Compile(pat)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bad match pattern %q: %v", pat, err)
|
||||
}
|
||||
return rx, nil
|
||||
}
|
||||
|
||||
func render(fset *token.FileSet, x interface{}) string {
|
||||
var buf bytes.Buffer
|
||||
if err := printer.Fprint(&buf, fset, x); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func TestLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
src string
|
||||
offset int
|
||||
want string
|
||||
}{
|
||||
{"single line file", 5, "single line file"},
|
||||
{"single line file with newline\n", 5, "single line file with newline\n"},
|
||||
{"first\nsecond\nthird\n", 2, "first\n"},
|
||||
{"first\nsecond\nthird\n", 9, "second\n"},
|
||||
{"first\nsecond\nthird\n", 14, "third\n"},
|
||||
{"first\nsecond\nthird with no newline", 16, "third with no newline"},
|
||||
{"first byte\n", 0, "first byte\n"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
got := srcLine([]byte(test.src), token.Position{Offset: test.offset})
|
||||
if got != test.want {
|
||||
t.Errorf("srcLine(%q, offset=%d) = %q, want %q", test.src, test.offset, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLintName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name, want string
|
||||
}{
|
||||
{"foo_bar", "fooBar"},
|
||||
{"foo_bar_baz", "fooBarBaz"},
|
||||
{"Foo_bar", "FooBar"},
|
||||
{"foo_WiFi", "fooWiFi"},
|
||||
{"id", "id"},
|
||||
{"Id", "ID"},
|
||||
{"foo_id", "fooID"},
|
||||
{"fooId", "fooID"},
|
||||
{"fooUid", "fooUID"},
|
||||
{"idFoo", "idFoo"},
|
||||
{"uidFoo", "uidFoo"},
|
||||
{"midIdDle", "midIDDle"},
|
||||
{"APIProxy", "APIProxy"},
|
||||
{"ApiProxy", "APIProxy"},
|
||||
{"apiProxy", "apiProxy"},
|
||||
{"_Leading", "_Leading"},
|
||||
{"___Leading", "_Leading"},
|
||||
{"trailing_", "trailing"},
|
||||
{"trailing___", "trailing"},
|
||||
{"a_b", "aB"},
|
||||
{"a__b", "aB"},
|
||||
{"a___b", "aB"},
|
||||
{"Rpc1150", "RPC1150"},
|
||||
{"case3_1", "case3_1"},
|
||||
{"case3__1", "case3_1"},
|
||||
{"IEEE802_16bit", "IEEE802_16bit"},
|
||||
{"IEEE802_16Bit", "IEEE802_16Bit"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
got := lintName(test.name)
|
||||
if got != test.want {
|
||||
t.Errorf("lintName(%q) = %q, want %q", test.name, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExportedType(t *testing.T) {
|
||||
tests := []struct {
|
||||
typString string
|
||||
exp bool
|
||||
}{
|
||||
{"int", true},
|
||||
{"string", false}, // references the shadowed builtin "string"
|
||||
{"T", true},
|
||||
{"t", false},
|
||||
{"*T", true},
|
||||
{"*t", false},
|
||||
{"map[int]complex128", true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
src := `package foo; type T int; type t int; type string struct{}`
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "foo.go", src, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Parsing %q: %v", src, err)
|
||||
}
|
||||
// use the package name as package path
|
||||
pkg, err := types.Check(file.Name.Name, fset, []*ast.File{file})
|
||||
if err != nil {
|
||||
t.Fatalf("Type checking %q: %v", src, err)
|
||||
}
|
||||
// Use the first child scope of the package, which will be the file scope.
|
||||
scope := pkg.Scope().Child(0)
|
||||
tv, err := types.Eval(test.typString, pkg, scope)
|
||||
if err != nil {
|
||||
t.Errorf("types.Eval(%q): %v", test.typString, err)
|
||||
continue
|
||||
}
|
||||
if got := exportedType(tv.Type); got != test.exp {
|
||||
t.Errorf("exportedType(%v) = %t, want %t", tv.Type, got, test.exp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
;;; golint.el --- lint for the Go source code
|
||||
|
||||
;; Copyright 2013 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.
|
||||
|
||||
;; URL: https://github.com/golang/lint
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; To install golint, add the following lines to your .emacs file:
|
||||
;; (add-to-list 'load-path "PATH CONTAINING golint.el" t)
|
||||
;; (require 'golint)
|
||||
;;
|
||||
;; After this, type M-x golint on Go source code.
|
||||
;;
|
||||
;; Usage:
|
||||
;; C-x `
|
||||
;; Jump directly to the line in your code which caused the first message.
|
||||
;;
|
||||
;; For more usage, see Compilation-Mode:
|
||||
;; http://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html
|
||||
|
||||
;;; Code:
|
||||
(require 'compile)
|
||||
|
||||
(defun go-lint-buffer-name (mode)
|
||||
"*Golint*")
|
||||
|
||||
(defun golint-process-setup ()
|
||||
"Setup compilation variables and buffer for `golint'."
|
||||
(run-hooks 'golint-setup-hook))
|
||||
|
||||
(define-compilation-mode golint-mode "golint"
|
||||
"Golint is a linter for Go source code."
|
||||
(set (make-local-variable 'compilation-scroll-output) nil)
|
||||
(set (make-local-variable 'compilation-disable-input) t)
|
||||
(set (make-local-variable 'compilation-process-setup-function)
|
||||
'golint-process-setup)
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defun golint ()
|
||||
"Run golint on the current file and populate the fix list. Pressing C-x ` will jump directly to the line in your code which caused the first message."
|
||||
(interactive)
|
||||
(compilation-start (concat "golint " buffer-file-name)
|
||||
'golint-mode))
|
||||
|
||||
(provide 'golint)
|
||||
|
||||
;;; golint.el ends here
|
||||
@@ -0,0 +1,31 @@
|
||||
" Copyright 2013 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.
|
||||
"
|
||||
" lint.vim: Vim command to lint Go files with golint.
|
||||
"
|
||||
" https://github.com/golang/lint
|
||||
"
|
||||
" This filetype plugin add a new commands for go buffers:
|
||||
"
|
||||
" :Lint
|
||||
"
|
||||
" Run golint for the current Go file.
|
||||
"
|
||||
if exists("b:did_ftplugin_go_lint")
|
||||
finish
|
||||
endif
|
||||
|
||||
if !executable("golint")
|
||||
finish
|
||||
endif
|
||||
|
||||
command! -buffer Lint call s:GoLint()
|
||||
|
||||
function! s:GoLint() abort
|
||||
cexpr system('golint ' . shellescape(expand('%')))
|
||||
endfunction
|
||||
|
||||
let b:did_ftplugin_go_lint = 1
|
||||
|
||||
" vim:ts=4:sw=4:et
|
||||
@@ -0,0 +1,34 @@
|
||||
// Test that exported names have correct comments.
|
||||
|
||||
// Package pkg does something.
|
||||
package pkg
|
||||
|
||||
import "time"
|
||||
|
||||
type T int // MATCH /exported type T.*should.*comment.*or.*unexport/
|
||||
|
||||
func (T) F() {} // MATCH /exported method T\.F.*should.*comment.*or.*unexport/
|
||||
|
||||
// this is a nice type.
|
||||
// MATCH /comment.*exported type U.*should.*form.*"U ..."/
|
||||
type U string
|
||||
|
||||
// this is a neat function.
|
||||
// MATCH /comment.*exported method U\.G.*should.*form.*"G ..."/
|
||||
func (U) G() {}
|
||||
|
||||
// A V is a string.
|
||||
type V string
|
||||
|
||||
// V.H has a pointer receiver
|
||||
|
||||
func (*V) H() {} // MATCH /exported method V\.H.*should.*comment.*or.*unexport/
|
||||
|
||||
var W = "foo" // MATCH /exported var W.*should.*comment.*or.*unexport/
|
||||
|
||||
const X = "bar" // MATCH /exported const X.*should.*comment.*or.*unexport/
|
||||
|
||||
var Y, Z int // MATCH /exported var Z.*own declaration/
|
||||
|
||||
// Location should be okay, since the other var name is an underscore.
|
||||
var Location, _ = time.LoadLocation("Europe/Istanbul") // not Constantinople
|
||||
@@ -0,0 +1,17 @@
|
||||
// This file ends in _test.go, so we should not warn about doc comments.
|
||||
// OK
|
||||
|
||||
package pkg
|
||||
|
||||
import "testing"
|
||||
|
||||
type H int
|
||||
|
||||
func TestSomething(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSomething_suffix(t *testing.T) {
|
||||
}
|
||||
|
||||
func ExampleBuffer_reader() {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Test that blank imports in library packages are flagged.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
// The instructions need to go before the imports below so they will not be
|
||||
// mistaken for documentation.
|
||||
|
||||
/* MATCH /blank import/ */ import _ "encoding/json"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
/* MATCH /blank import/ */ _ "os"
|
||||
|
||||
/* MATCH /blank import/ */ _ "net/http"
|
||||
_ "path"
|
||||
)
|
||||
|
||||
import _ "encoding/base64" // Don't gripe about this
|
||||
|
||||
import (
|
||||
// Don't gripe about these next two lines.
|
||||
_ "compress/zlib"
|
||||
_ "syscall"
|
||||
|
||||
/* MATCH /blank import/ */ _ "path/filepath"
|
||||
)
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
_ "go/scanner" // Don't gripe about this or the following line.
|
||||
_ "go/token"
|
||||
)
|
||||
|
||||
var (
|
||||
_ fmt.Stringer // for "fmt"
|
||||
_ ast.Node // for "go/ast"
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
// Test that blank imports in test packages are not flagged.
|
||||
// OK
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
// These are essentially the same imports as in the "library" package, but
|
||||
// these should not trigger the warning because this is a test.
|
||||
|
||||
import _ "encoding/json"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
_ "os"
|
||||
|
||||
_ "net/http"
|
||||
_ "path"
|
||||
)
|
||||
|
||||
var (
|
||||
_ fmt.Stringer // for "fmt"
|
||||
_ testing.T // for "testing"
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
// Test that blank imports in package main are not flagged.
|
||||
// OK
|
||||
|
||||
// Binary foo ...
|
||||
package main
|
||||
|
||||
import _ "fmt"
|
||||
|
||||
import (
|
||||
"os"
|
||||
_ "path"
|
||||
)
|
||||
|
||||
var _ os.File // for "os"
|
||||
@@ -0,0 +1,16 @@
|
||||
// Test that we don't nag for comments on common methods.
|
||||
// OK
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
import "net/http"
|
||||
|
||||
// T is ...
|
||||
type T int
|
||||
|
||||
func (T) Error() string { return "" }
|
||||
func (T) String() string { return "" }
|
||||
func (T) ServeHTTP(w http.ResponseWriter, r *http.Request) {}
|
||||
func (T) Read(p []byte) (n int, err error) { return 0, nil }
|
||||
func (T) Write(p []byte) (n int, err error) { return 0, nil }
|
||||
@@ -0,0 +1,36 @@
|
||||
// Test for docs in const blocks
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
const (
|
||||
// Prefix for something.
|
||||
// MATCH /InlineWhatever.*form/
|
||||
InlineWhatever = "blah"
|
||||
|
||||
Whatsit = "missing_comment" // MATCH /Whatsit.*should have comment.*block/
|
||||
|
||||
// We should only warn once per block for missing comments,
|
||||
// but always complain about malformed comments.
|
||||
|
||||
WhosYourDaddy = "another_missing_one"
|
||||
|
||||
// Something
|
||||
// MATCH /WhatDoesHeDo.*form/
|
||||
WhatDoesHeDo = "it's not a tumor!"
|
||||
)
|
||||
|
||||
// These shouldn't need doc comments.
|
||||
const (
|
||||
Alpha = "a"
|
||||
Beta = "b"
|
||||
Gamma = "g"
|
||||
)
|
||||
|
||||
// The comment on the previous const block shouldn't flow through to here.
|
||||
|
||||
const UndocAgain = 6 // MATCH /UndocAgain.*should have comment/
|
||||
|
||||
const (
|
||||
SomeUndocumented = 7 // MATCH /SomeUndocumented.*should have comment.*block/
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
// Test of return+else warning; should not trigger on multi-branch if/else.
|
||||
// OK
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
import "log"
|
||||
|
||||
func f(x int) bool {
|
||||
if x == 0 {
|
||||
log.Print("x is zero")
|
||||
} else if x > 0 {
|
||||
return true
|
||||
} else {
|
||||
log.Printf("non-positive x: %d", x)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Test of return+else warning.
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
import "log"
|
||||
|
||||
func f(x int) bool {
|
||||
if x > 0 {
|
||||
return true
|
||||
} else { // MATCH /if.*return.*else.*outdent/
|
||||
log.Printf("non-positive x: %d", x)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func g(f func() bool) string {
|
||||
if ok := f(); ok {
|
||||
return "it's okay"
|
||||
} else { // MATCH /if.*return.*else.*outdent.*short.*var.*declaration/
|
||||
return "it's NOT okay!"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Test for returning errors.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
// Returns nothing
|
||||
func f() { // ok
|
||||
}
|
||||
|
||||
// Check for a single error return
|
||||
func g() error { // ok
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check for a single other return type
|
||||
func h() int { // ok
|
||||
return 0
|
||||
}
|
||||
|
||||
// Check for multiple return but error at end.
|
||||
func i() (int, error) { // ok
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Check for multiple return but error at end with named variables.
|
||||
func j() (x int, err error) { // ok
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Check for error in the wrong location on 2 types
|
||||
func k() (error, int) { // MATCH /error should be the last type/
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
// Check for error in the wrong location for > 2 types
|
||||
func l() (int, error, int) { // MATCH /error should be the last type/
|
||||
return 0, nil, 0
|
||||
}
|
||||
|
||||
// Check for error in the wrong location with named variables.
|
||||
func m() (x int, err error, y int) { // MATCH /error should be the last type/
|
||||
return 0, nil, 0
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Test for not using fmt.Errorf.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func f(x int) error {
|
||||
if x > 10 {
|
||||
return errors.New(fmt.Sprintf("something %d", x)) // MATCH /should replace.*errors\.New\(fmt\.Sprintf\(\.\.\.\)\).*fmt\.Errorf\(\.\.\.\)/
|
||||
}
|
||||
if x > 5 {
|
||||
return errors.New(g("blah")) // ok
|
||||
}
|
||||
if x > 4 {
|
||||
return errors.New("something else") // ok
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func g(s string) string { return "prefix: " + s }
|
||||
@@ -0,0 +1,36 @@
|
||||
// Test for naming errors.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var unexp = errors.New("some unexported error") // MATCH /error var.*unexp.*errFoo/
|
||||
|
||||
// Exp ...
|
||||
var Exp = errors.New("some exported error") // MATCH /error var.*Exp.*ErrFoo/
|
||||
|
||||
var (
|
||||
e1 = fmt.Errorf("blah %d", 4) // MATCH /error var.*e1.*errFoo/
|
||||
// E2 ...
|
||||
E2 = fmt.Errorf("blah %d", 5) // MATCH /error var.*E2.*ErrFoo/
|
||||
)
|
||||
|
||||
func f() {
|
||||
var whatever = errors.New("ok") // ok
|
||||
_ = whatever
|
||||
}
|
||||
|
||||
// Check for the error strings themselves.
|
||||
|
||||
func g(x int) error {
|
||||
if x < 1 {
|
||||
return fmt.Errorf("This %d is too low", x) // MATCH /error strings.*not be capitalized/
|
||||
} else if x == 0 {
|
||||
return fmt.Errorf("XML time") // ok
|
||||
}
|
||||
return errors.New(`too much stuff.`) // MATCH /error strings.*not end with punctuation/
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Test that dot imports are flagged.
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
import . "fmt" // MATCH /dot import/
|
||||
|
||||
var _ Stringer // from "fmt"
|
||||
@@ -0,0 +1,14 @@
|
||||
// Test for use of x++ and x--.
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
func addOne(x int) int {
|
||||
x += 1 // MATCH /x\+\+/
|
||||
return x
|
||||
}
|
||||
|
||||
func subOneInLoop(y int) {
|
||||
for ; y > 0; y -= 1 { // MATCH /y--/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Test for pointless make() calls.
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
import "net/http"
|
||||
|
||||
// T is a test type.
|
||||
type T int
|
||||
|
||||
var z []T
|
||||
|
||||
func f() {
|
||||
x := make([]T, 0) // MATCH /var x \[\]T/
|
||||
y := make([]http.Request, 0) // MATCH /var y \[\]http\.Request/
|
||||
z = make([]T, 0) // ok, because we don't know where z is declared
|
||||
|
||||
_, _ = x, y
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Test for name linting.
|
||||
|
||||
// Package pkg_with_underscores ...
|
||||
package pkg_with_underscores // MATCH /underscore.*package name/
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
net_http "net/http" // renamed deliberately
|
||||
"net/url"
|
||||
)
|
||||
|
||||
var var_name int // MATCH /underscore.*var.*var_name/
|
||||
|
||||
type t_wow struct { // MATCH /underscore.*type.*t_wow/
|
||||
x_damn int // MATCH /underscore.*field.*x_damn/
|
||||
Url *url.URL // MATCH /struct field.*Url.*URL/
|
||||
}
|
||||
|
||||
const fooId = "blah" // MATCH /fooId.*fooID/
|
||||
|
||||
func f_it() { // MATCH /underscore.*func.*f_it/
|
||||
more_underscore := 4 // MATCH /underscore.*var.*more_underscore/
|
||||
_ = more_underscore
|
||||
var err error
|
||||
if isEof := (err == io.EOF); isEof { // MATCH /var.*isEof.*isEOF/
|
||||
more_underscore = 7 // should be okay
|
||||
}
|
||||
|
||||
x := net_http.Request{} // should be okay
|
||||
_ = x
|
||||
|
||||
var ips []net.IP
|
||||
for _, theIp := range ips { // MATCH /range var.*theIp.*theIP/
|
||||
_ = theIp
|
||||
}
|
||||
|
||||
switch myJson := g(); { // MATCH /var.*myJson.*myJSON/
|
||||
default:
|
||||
_ = myJson
|
||||
}
|
||||
var y net_http.ResponseWriter // an interface
|
||||
switch tApi := y.(type) { // MATCH /var.*tApi.*tAPI/
|
||||
default:
|
||||
_ = tApi
|
||||
}
|
||||
|
||||
var c chan int
|
||||
select {
|
||||
case qId := <-c: // MATCH /var.*qId.*qID/
|
||||
_ = qId
|
||||
}
|
||||
}
|
||||
|
||||
// Common styles in other languages that don't belong in Go.
|
||||
const (
|
||||
CPP_CONST = 1 // MATCH /ALL_CAPS.*CamelCase/
|
||||
kLeadingKay = 2 // MATCH /k.*leadingKay/
|
||||
|
||||
HTML = 3 // okay; no underscore
|
||||
X509B = 4 // ditto
|
||||
)
|
||||
|
||||
func f(bad_name int) {} // MATCH /underscore.*func parameter.*bad_name/
|
||||
func g() (no_way int) { return 0 } // MATCH /underscore.*func result.*no_way/
|
||||
func (t *t_wow) f(more_under string) {} // MATCH /underscore.*method parameter.*more_under/
|
||||
func (t *t_wow) g() (still_more string) { return "" } // MATCH /underscore.*method result.*still_more/
|
||||
|
||||
type i interface {
|
||||
CheckHtml() string // okay; interface method names are often constrained by the concrete types' method names
|
||||
|
||||
F(foo_bar int) // MATCH /foo_bar.*fooBar/
|
||||
}
|
||||
|
||||
// All okay; underscore between digits
|
||||
const case1_1 = 1
|
||||
|
||||
type case2_1 struct {
|
||||
case2_2 int
|
||||
}
|
||||
|
||||
func case3_1(case3_2 int) (case3_3 string) {
|
||||
case3_4 := 4
|
||||
_ = case3_4
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// Test of missing package comment.
|
||||
|
||||
package foo // MATCH /should.*package comment.*unless/
|
||||
@@ -0,0 +1,5 @@
|
||||
// Test of package comment in an incorrect form.
|
||||
|
||||
// Some random package doc that isn't in the right form.
|
||||
// MATCH /package comment should.*form.*"Package testdata .*"/
|
||||
package testdata
|
||||
@@ -0,0 +1,7 @@
|
||||
// Test of block package comment.
|
||||
// OK
|
||||
|
||||
/*
|
||||
Package foo is pretty sweet.
|
||||
*/
|
||||
package foo
|
||||
@@ -0,0 +1,7 @@
|
||||
// Test of block package comment with leading space.
|
||||
|
||||
/*
|
||||
Package foo is pretty sweet.
|
||||
MATCH /package comment.*leading space/
|
||||
*/
|
||||
package foo
|
||||
@@ -0,0 +1,9 @@
|
||||
// Test of detached package comment.
|
||||
|
||||
/*
|
||||
Package foo is pretty sweet.
|
||||
*/
|
||||
|
||||
package foo
|
||||
|
||||
// MATCH:6 /package comment.*detached/
|
||||
@@ -0,0 +1,5 @@
|
||||
// Test of package comment for package main.
|
||||
// OK
|
||||
|
||||
// This binary does something awesome.
|
||||
package main
|
||||
@@ -0,0 +1,37 @@
|
||||
// Test for range construction.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
func f() {
|
||||
var m map[string]int
|
||||
|
||||
// with :=
|
||||
for x, _ := range m { // MATCH /should omit 2nd value.*range.*equivalent.*for x := range/
|
||||
_ = x
|
||||
}
|
||||
// with =
|
||||
var y string
|
||||
_ = y
|
||||
for y, _ = range m { // MATCH /should omit 2nd value.*range.*equivalent.*for y = range/
|
||||
}
|
||||
|
||||
// all OK:
|
||||
for x := range m {
|
||||
_ = x
|
||||
}
|
||||
for x, y := range m {
|
||||
_, _ = x, y
|
||||
}
|
||||
for _, y := range m {
|
||||
_ = y
|
||||
}
|
||||
var x int
|
||||
_ = x
|
||||
for y = range m {
|
||||
}
|
||||
for y, x = range m {
|
||||
}
|
||||
for _, x = range m {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Test for bad receiver names.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func (this foo) f1() { // MATCH /should be a reflection of its identity/
|
||||
}
|
||||
|
||||
func (self foo) f2() { // MATCH /should be a reflection of its identity/
|
||||
}
|
||||
|
||||
func (f foo) f3() {
|
||||
}
|
||||
|
||||
func (foo) f4() {
|
||||
}
|
||||
|
||||
type bar struct{}
|
||||
|
||||
func (b bar) f1() {
|
||||
}
|
||||
|
||||
func (b bar) f2() {
|
||||
}
|
||||
|
||||
func (a bar) f3() { // MATCH /receiver name a should be consistent with previous receiver name b for bar/
|
||||
}
|
||||
|
||||
func (a *bar) f4() { // MATCH /receiver name a should be consistent with previous receiver name b for bar/
|
||||
}
|
||||
|
||||
func (b *bar) f5() {
|
||||
}
|
||||
|
||||
func (bar) f6() {
|
||||
}
|
||||
|
||||
func (_ *bar) f7() { // MATCH /receiver name should not be an underscore/
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Test that we don't ask for comments on sort.Interface methods.
|
||||
|
||||
// Package pkg ...
|
||||
package pkg
|
||||
|
||||
// T is ...
|
||||
type T []int
|
||||
|
||||
// Len by itself should get documented.
|
||||
|
||||
func (t T) Len() int { return len(t) } // MATCH /exported method T\.Len.*should.*comment/
|
||||
|
||||
// U is ...
|
||||
type U []int
|
||||
|
||||
func (u U) Len() int { return len(u) }
|
||||
func (u U) Less(i, j int) bool { return u[i] < u[j] }
|
||||
func (u U) Swap(i, j int) { u[i], u[j] = u[j], u[i] }
|
||||
|
||||
func (u U) Other() {} // MATCH /exported method U\.Other.*should.*comment/
|
||||
@@ -0,0 +1,25 @@
|
||||
// Test of stuttery names.
|
||||
|
||||
// Package donut ...
|
||||
package donut
|
||||
|
||||
// DonutMaker makes donuts.
|
||||
type DonutMaker struct{} // MATCH /donut\.DonutMaker.*stutter/
|
||||
|
||||
// DonutRank computes the ranking of a donut.
|
||||
func DonutRank(d Donut) int { // MATCH /donut\.DonutRank.*stutter/
|
||||
return 0
|
||||
}
|
||||
|
||||
// Donut is a delicious treat.
|
||||
type Donut struct{} // ok because it is the whole name
|
||||
|
||||
// Donuts are great, aren't they?
|
||||
type Donuts []Donut // ok because it didn't start a new word
|
||||
|
||||
type donutGlaze int // ok because it is unexported
|
||||
|
||||
// DonutMass reports the mass of a donut.
|
||||
func (d *Donut) DonutMass() (grams int) { // okay because it is a method
|
||||
return 38
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Test of time suffixes.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"time"
|
||||
)
|
||||
|
||||
var rpcTimeoutMsec = flag.Duration("rpc_timeout", 100*time.Millisecond, "some flag") // MATCH /Msec.*\*time.Duration/
|
||||
|
||||
var timeoutSecs = 5 * time.Second // MATCH /Secs.*time.Duration/
|
||||
@@ -0,0 +1,46 @@
|
||||
// Test for unexported return types.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import ()
|
||||
|
||||
type hidden struct{}
|
||||
|
||||
// Exported returns a hidden type, which is annoying.
|
||||
func Exported() hidden { // MATCH /Exported.*unexported.*hidden/
|
||||
return hidden{}
|
||||
}
|
||||
|
||||
// ExpErr returns a builtin type.
|
||||
func ExpErr() error { // ok
|
||||
}
|
||||
|
||||
func (hidden) ExpOnHidden() hidden { // ok
|
||||
}
|
||||
|
||||
// T is another test type.
|
||||
type T struct{}
|
||||
|
||||
// MethodOnT returns a hidden type, which is annoying.
|
||||
func (T) MethodOnT() hidden { // MATCH /method MethodOnT.*unexported.*hidden/
|
||||
return hidden{}
|
||||
}
|
||||
|
||||
// ExpT returns a T.
|
||||
func ExpT() T { // ok
|
||||
return T{}
|
||||
}
|
||||
|
||||
func unexp() hidden { // ok
|
||||
return hidden{}
|
||||
}
|
||||
|
||||
// This is slightly sneaky: we shadow the builtin "int" type.
|
||||
|
||||
type int struct{}
|
||||
|
||||
// ExportedIntReturner returns an unexported type from this package.
|
||||
func ExportedIntReturner() int { // MATCH /ExportedIntReturner.*unexported.*int/
|
||||
return int{}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Test for redundant type declaration.
|
||||
|
||||
// Package foo ...
|
||||
package foo
|
||||
|
||||
import "fmt"
|
||||
import "net/http"
|
||||
|
||||
// Q is a test type.
|
||||
type Q bool
|
||||
|
||||
var myInt int = 7 // MATCH /should.*int.*myInt.*inferred/
|
||||
var mux *http.ServeMux = http.NewServeMux() // MATCH /should.*\*http\.ServeMux.*inferred/
|
||||
|
||||
var myZeroInt int = 0 // MATCH /should.*= 0.*myZeroInt.*zero value/
|
||||
var myZeroFlt float32 = 0. // MATCH /should.*= 0\..*myZeroFlt.*zero value/
|
||||
var myZeroF64 float64 = 0.0 // MATCH /should.*= 0\..*myZeroF64.*zero value/
|
||||
var myZeroImg complex64 = 0i // MATCH /should.*= 0i.*myZeroImg.*zero value/
|
||||
var myZeroStr string = "" // MATCH /should.*= "".*myZeroStr.*zero value/
|
||||
var myZeroRaw string = `` // MATCH /should.*= ``.*myZeroRaw.*zero value/
|
||||
var myZeroPtr *Q = nil // MATCH /should.*= nil.*myZeroPtr.*zero value/
|
||||
var myZeroRune rune = '\x00' // MATCH /should.*= '\\x00'.*myZeroRune.*zero value/
|
||||
var myZeroRune2 rune = '\000' // MATCH /should.*= '\\000'.*myZeroRune2.*zero value/
|
||||
|
||||
// No warning because there's no type on the LHS
|
||||
var x = 0
|
||||
|
||||
// This shouldn't get a warning because there's no initial values.
|
||||
var str fmt.Stringer
|
||||
|
||||
// No warning because this is a const.
|
||||
const k uint64 = 7
|
||||
|
||||
const num = 123
|
||||
|
||||
// No warning because the var's RHS is known to be an untyped const.
|
||||
var flags uint32 = num
|
||||
|
||||
// No warnings because the RHS is an ideal int, and the LHS is a different int type.
|
||||
var userID int64 = 1235
|
||||
var negID int64 = -1
|
||||
var parenID int64 = (17)
|
||||
var crazyID int64 = -(-(-(-9)))
|
||||
|
||||
// Same, but for strings and floats.
|
||||
type stringT string
|
||||
type floatT float64
|
||||
|
||||
var stringV stringT = "abc"
|
||||
var floatV floatT = 123.45
|
||||
|
||||
// No warning because the LHS names an interface type.
|
||||
var data interface{} = googleIPs
|
||||
var googleIPs []int
|
||||
|
||||
// No warning because it's a common idiom for interface satisfaction.
|
||||
var _ Server = (*serverImpl)(nil)
|
||||
|
||||
// Server is a test type.
|
||||
type Server interface{}
|
||||
type serverImpl struct{}
|
||||
|
||||
// LHS is a different type than the RHS.
|
||||
var myStringer fmt.Stringer = q(0)
|
||||
|
||||
var y string = q(1).String() // MATCH /should.*string/
|
||||
|
||||
type q int
|
||||
|
||||
func (q) String() string { return "I'm a q" }
|
||||
Reference in new issue
Block a user