initial vendor commit

This commit is contained in:
swaits committed 2015-02-14 21:53:22 -08:00
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.
[![Build Status](https://travis-ci.org/golang/lint.svg?branch=master)](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
+34
View File
@@ -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
+17
View File
@@ -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
}
+23
View File
@@ -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
}
+24
View File
@@ -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 }
+36
View File
@@ -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"
+14
View File
@@ -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--/
}
}
+19
View File
@@ -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
}
+87
View File
@@ -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
+37
View File
@@ -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/
}
+20
View File
@@ -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/
+25
View File
@@ -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
}
+13
View File
@@ -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{}
}
+70
View File
@@ -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" }