New upstream version 0.0+git20200130.910be7a
Anthony Fok
4 years ago
0 | sudo: false | |
0 | 1 | language: go |
1 | 2 | go: |
2 | - 1.6 | |
3 | - 1.7 | |
3 | - 1.10.x | |
4 | - 1.11.x | |
5 | - master | |
6 | ||
7 | go_import_path: golang.org/x/lint | |
4 | 8 | |
5 | 9 | install: |
6 | 10 | - go get -t -v ./... |
7 | 11 | |
8 | 12 | script: |
9 | - go test -v ./... | |
13 | - go test -v -race ./... | |
14 | ||
15 | matrix: | |
16 | allow_failures: | |
17 | - go: master | |
18 | fast_finish: true |
5 | 5 | |
6 | 6 | Check you have the latest version of its dependencies. Run |
7 | 7 | ``` |
8 | go get -u github.com/golang/lint | |
8 | go get -u golang.org/x/lint/golint | |
9 | 9 | ``` |
10 | 10 | If you still have problems, consider searching for existing issues before filing a new issue. |
11 | 11 |
3 | 3 | |
4 | 4 | ## Installation |
5 | 5 | |
6 | Golint requires Go 1.6 or later. | |
6 | Golint requires a | |
7 | [supported release of Go](https://golang.org/doc/devel/release.html#policy). | |
7 | 8 | |
8 | go get -u github.com/golang/lint/golint | |
9 | go get -u golang.org/x/lint/golint | |
10 | ||
11 | To find out where `golint` was installed you can run `go list -f {{.Target}} golang.org/x/lint/golint`. For `golint` to be used globally add that directory to the `$PATH` environment setting. | |
9 | 12 | |
10 | 13 | ## Usage |
11 | 14 | |
12 | Invoke `golint` with one or more filenames, a directory, or a package named | |
15 | Invoke `golint` with one or more filenames, directories, or packages named | |
13 | 16 | by its import path. Golint uses the same |
14 | 17 | [import path syntax](https://golang.org/cmd/go/#hdr-Import_path_syntax) as |
15 | 18 | the `go` command and therefore |
40 | 43 | [Effective Go](https://golang.org/doc/effective_go.html) and the |
41 | 44 | [CodeReviewComments wiki page](https://golang.org/wiki/CodeReviewComments). |
42 | 45 | |
43 | If you find an established style that is frequently violated, and which | |
44 | you think golint could statically check, | |
45 | [file an issue](https://github.com/golang/lint/issues). | |
46 | ## Scope | |
47 | ||
48 | Golint is meant to carry out the stylistic conventions put forth in | |
49 | [Effective Go](https://golang.org/doc/effective_go.html) and | |
50 | [CodeReviewComments](https://golang.org/wiki/CodeReviewComments). | |
51 | Changes that are not aligned with those documents will not be considered. | |
46 | 52 | |
47 | 53 | ## Contributions |
48 | 54 | |
49 | Contributions to this project are welcome, though please send mail before | |
50 | starting work on anything major. Contributors retain their copyright, so we | |
51 | need you to fill out | |
55 | Contributions to this project are welcome provided they are [in scope](#scope), | |
56 | though please send mail before starting work on anything major. | |
57 | Contributors retain their copyright, so we need you to fill out | |
52 | 58 | [a short form](https://developers.google.com/open-source/cla/individual) |
53 | 59 | before we can accept your contribution. |
54 | 60 | |
56 | 62 | |
57 | 63 | Add this to your ~/.vimrc: |
58 | 64 | |
59 | set rtp+=$GOPATH/src/github.com/golang/lint/misc/vim | |
65 | set rtp+=$GOPATH/src/golang.org/x/lint/misc/vim | |
60 | 66 | |
61 | 67 | If you have multiple entries in your GOPATH, replace `$GOPATH` with the right value. |
62 | 68 | |
71 | 77 | |
72 | 78 | Add this to your `.emacs` file: |
73 | 79 | |
74 | (add-to-list 'load-path (concat (getenv "GOPATH") "/src/github.com/golang/lint/misc/emacs")) | |
80 | (add-to-list 'load-path (concat (getenv "GOPATH") "/src/golang.org/x/lint/misc/emacs/")) | |
75 | 81 | (require 'golint) |
76 | 82 | |
77 | 83 | If you have multiple entries in your GOPATH, replace `$GOPATH` with the right value. |
0 | module golang.org/x/lint | |
1 | ||
2 | go 1.11 | |
3 | ||
4 | require golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 |
0 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |
1 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |
2 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | |
3 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |
4 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |
5 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
6 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
7 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
8 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |
9 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY= | |
10 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | |
11 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
15 | 15 | "path/filepath" |
16 | 16 | "strings" |
17 | 17 | |
18 | "github.com/golang/lint" | |
18 | "golang.org/x/lint" | |
19 | 19 | ) |
20 | 20 | |
21 | 21 | var ( |
27 | 27 | func usage() { |
28 | 28 | fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) |
29 | 29 | fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n") |
30 | fmt.Fprintf(os.Stderr, "\tgolint [flags] package\n") | |
31 | fmt.Fprintf(os.Stderr, "\tgolint [flags] directory\n") | |
32 | fmt.Fprintf(os.Stderr, "\tgolint [flags] files... # must be a single package\n") | |
30 | fmt.Fprintf(os.Stderr, "\tgolint [flags] [packages]\n") | |
31 | fmt.Fprintf(os.Stderr, "\tgolint [flags] [directories] # where a '/...' suffix includes all sub-directories\n") | |
32 | fmt.Fprintf(os.Stderr, "\tgolint [flags] [files] # all must belong to a single package\n") | |
33 | 33 | fmt.Fprintf(os.Stderr, "Flags:\n") |
34 | 34 | flag.PrintDefaults() |
35 | 35 | } |
38 | 38 | flag.Usage = usage |
39 | 39 | flag.Parse() |
40 | 40 | |
41 | switch flag.NArg() { | |
42 | case 0: | |
41 | if flag.NArg() == 0 { | |
43 | 42 | lintDir(".") |
44 | case 1: | |
45 | arg := flag.Arg(0) | |
46 | if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-4]) { | |
47 | for _, dirname := range allPackagesInFS(arg) { | |
48 | lintDir(dirname) | |
49 | } | |
50 | } else if isDir(arg) { | |
51 | lintDir(arg) | |
52 | } else if exists(arg) { | |
53 | lintFiles(arg) | |
54 | } else { | |
55 | for _, pkgname := range importPaths([]string{arg}) { | |
56 | lintPackage(pkgname) | |
43 | } else { | |
44 | // dirsRun, filesRun, and pkgsRun indicate whether golint is applied to | |
45 | // directory, file or package targets. The distinction affects which | |
46 | // checks are run. It is no valid to mix target types. | |
47 | var dirsRun, filesRun, pkgsRun int | |
48 | var args []string | |
49 | for _, arg := range flag.Args() { | |
50 | if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) { | |
51 | dirsRun = 1 | |
52 | for _, dirname := range allPackagesInFS(arg) { | |
53 | args = append(args, dirname) | |
54 | } | |
55 | } else if isDir(arg) { | |
56 | dirsRun = 1 | |
57 | args = append(args, arg) | |
58 | } else if exists(arg) { | |
59 | filesRun = 1 | |
60 | args = append(args, arg) | |
61 | } else { | |
62 | pkgsRun = 1 | |
63 | args = append(args, arg) | |
57 | 64 | } |
58 | 65 | } |
59 | default: | |
60 | lintFiles(flag.Args()...) | |
66 | ||
67 | if dirsRun+filesRun+pkgsRun != 1 { | |
68 | usage() | |
69 | os.Exit(2) | |
70 | } | |
71 | switch { | |
72 | case dirsRun == 1: | |
73 | for _, dir := range args { | |
74 | lintDir(dir) | |
75 | } | |
76 | case filesRun == 1: | |
77 | lintFiles(args...) | |
78 | case pkgsRun == 1: | |
79 | for _, pkg := range importPaths(args) { | |
80 | lintPackage(pkg) | |
81 | } | |
82 | } | |
61 | 83 | } |
62 | 84 | |
63 | 85 | if *setExitStatus && suggestions > 0 { |
21 | 21 | "strings" |
22 | 22 | ) |
23 | 23 | |
24 | var buildContext = build.Default | |
25 | ||
26 | 24 | var ( |
27 | goroot = filepath.Clean(runtime.GOROOT()) | |
28 | gorootSrc = filepath.Join(goroot, "src") | |
25 | buildContext = build.Default | |
26 | goroot = filepath.Clean(runtime.GOROOT()) | |
27 | gorootSrc = filepath.Join(goroot, "src") | |
29 | 28 | ) |
30 | 29 | |
31 | 30 | // importPathsNoDotExpansion returns the import paths to use for the given |
0 | // Copyright (c) 2018 The Go Authors. All rights reserved. | |
1 | // | |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file or at | |
4 | // https://developers.google.com/open-source/licenses/bsd. | |
5 | ||
6 | // +build go1.12 | |
7 | ||
8 | // Require use of the correct import path only for Go 1.12+ users, so | |
9 | // any breakages coincide with people updating their CI configs or | |
10 | // whatnot. | |
11 | ||
12 | package main // import "golang.org/x/lint/golint" |
4 | 4 | // https://developers.google.com/open-source/licenses/bsd. |
5 | 5 | |
6 | 6 | // Package lint contains a linter for Go source code. |
7 | package lint | |
7 | package lint // import "golang.org/x/lint" | |
8 | 8 | |
9 | 9 | import ( |
10 | "bufio" | |
10 | 11 | "bytes" |
11 | 12 | "fmt" |
12 | 13 | "go/ast" |
21 | 22 | "unicode" |
22 | 23 | "unicode/utf8" |
23 | 24 | |
24 | "golang.org/x/tools/go/gcimporter15" | |
25 | "golang.org/x/tools/go/ast/astutil" | |
26 | "golang.org/x/tools/go/gcexportdata" | |
25 | 27 | ) |
26 | 28 | |
27 | 29 | const styleGuideBase = "https://golang.org/wiki/CodeReviewComments" |
80 | 82 | // LintFiles lints a set of files of a single package. |
81 | 83 | // The argument is a map of filename to source. |
82 | 84 | func (l *Linter) LintFiles(files map[string][]byte) ([]Problem, error) { |
83 | if len(files) == 0 { | |
84 | return nil, nil | |
85 | } | |
86 | 85 | pkg := &pkg{ |
87 | 86 | fset: token.NewFileSet(), |
88 | 87 | files: make(map[string]*file), |
89 | 88 | } |
90 | 89 | var pkgName string |
91 | 90 | for filename, src := range files { |
91 | if isGenerated(src) { | |
92 | continue // See issue #239 | |
93 | } | |
92 | 94 | f, err := parser.ParseFile(pkg.fset, filename, src, parser.ParseComments) |
93 | 95 | if err != nil { |
94 | 96 | return nil, err |
106 | 108 | filename: filename, |
107 | 109 | } |
108 | 110 | } |
111 | if len(pkg.files) == 0 { | |
112 | return nil, nil | |
113 | } | |
109 | 114 | return pkg.lint(), nil |
115 | } | |
116 | ||
117 | var ( | |
118 | genHdr = []byte("// Code generated ") | |
119 | genFtr = []byte(" DO NOT EDIT.") | |
120 | ) | |
121 | ||
122 | // isGenerated reports whether the source file is generated code | |
123 | // according the rules from https://golang.org/s/generatedcode. | |
124 | func isGenerated(src []byte) bool { | |
125 | sc := bufio.NewScanner(bytes.NewReader(src)) | |
126 | for sc.Scan() { | |
127 | b := sc.Bytes() | |
128 | if bytes.HasPrefix(b, genHdr) && bytes.HasSuffix(b, genFtr) && len(b) >= len(genHdr)+len(genFtr) { | |
129 | return true | |
130 | } | |
131 | } | |
132 | return false | |
110 | 133 | } |
111 | 134 | |
112 | 135 | // pkg represents a package being linted. |
174 | 197 | f.lintBlankImports() |
175 | 198 | f.lintExported() |
176 | 199 | f.lintNames() |
177 | f.lintVarDecls() | |
178 | 200 | f.lintElses() |
179 | 201 | f.lintRanges() |
180 | 202 | f.lintErrorf() |
234 | 256 | return &p.problems[len(p.problems)-1] |
235 | 257 | } |
236 | 258 | |
237 | var gcImporter = gcimporter.Import | |
238 | ||
239 | // importer implements go/types.Importer{,From}. | |
240 | type importer struct { | |
241 | impFn func(packages map[string]*types.Package, path, srcDir string) (*types.Package, error) | |
242 | packages map[string]*types.Package | |
243 | } | |
244 | ||
245 | func (i importer) Import(path string) (*types.Package, error) { | |
246 | return i.impFn(i.packages, path, "") | |
247 | } | |
248 | ||
249 | func (i importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) { | |
250 | return i.impFn(i.packages, path, srcDir) | |
259 | var newImporter = func(fset *token.FileSet) types.ImporterFrom { | |
260 | return gcexportdata.NewImporter(fset, make(map[string]*types.Package)) | |
251 | 261 | } |
252 | 262 | |
253 | 263 | func (p *pkg) typeCheck() error { |
254 | 264 | config := &types.Config{ |
255 | 265 | // By setting a no-op error reporter, the type checker does as much work as possible. |
256 | Error: func(error) {}, | |
257 | Importer: importer{ | |
258 | impFn: gcImporter, | |
259 | packages: make(map[string]*types.Package), | |
260 | }, | |
266 | Error: func(error) {}, | |
267 | Importer: newImporter(p.fset), | |
261 | 268 | } |
262 | 269 | info := &types.Info{ |
263 | 270 | Types: make(map[ast.Expr]types.TypeAndValue), |
453 | 460 | |
454 | 461 | // lintImports examines import blocks. |
455 | 462 | func (f *file) lintImports() { |
456 | ||
457 | 463 | for i, is := range f.f.Imports { |
458 | 464 | _ = i |
459 | 465 | if is.Name != nil && is.Name.Name == "." && !f.isTest() { |
461 | 467 | } |
462 | 468 | |
463 | 469 | } |
464 | ||
465 | 470 | } |
466 | 471 | |
467 | 472 | const docCommentsLink = styleGuideBase + "#doc-comments" |
520 | 525 | }) |
521 | 526 | } |
522 | 527 | |
523 | var allCapsRE = regexp.MustCompile(`^[A-Z0-9_]+$`) | |
528 | var ( | |
529 | allCapsRE = regexp.MustCompile(`^[A-Z0-9_]+$`) | |
530 | anyCapsRE = regexp.MustCompile(`[A-Z]`) | |
531 | ) | |
524 | 532 | |
525 | 533 | // knownNameExceptions is a set of names that are known to be exempt from naming checks. |
526 | 534 | // This is usually because they are constrained by having to match names in the |
530 | 538 | "kWh": true, |
531 | 539 | } |
532 | 540 | |
541 | func isInTopLevel(f *ast.File, ident *ast.Ident) bool { | |
542 | path, _ := astutil.PathEnclosingInterval(f, ident.Pos(), ident.End()) | |
543 | for _, f := range path { | |
544 | switch f.(type) { | |
545 | case *ast.File, *ast.GenDecl, *ast.ValueSpec, *ast.Ident: | |
546 | continue | |
547 | } | |
548 | return false | |
549 | } | |
550 | return true | |
551 | } | |
552 | ||
533 | 553 | // lintNames examines all names in the file. |
534 | 554 | // It complains if any use underscores or incorrect known initialisms. |
535 | 555 | func (f *file) lintNames() { |
537 | 557 | if strings.Contains(f.f.Name.Name, "_") && !strings.HasSuffix(f.f.Name.Name, "_test") { |
538 | 558 | f.errorf(f.f, 1, link("http://golang.org/doc/effective_go.html#package-names"), category("naming"), "don't use an underscore in package name") |
539 | 559 | } |
560 | if anyCapsRE.MatchString(f.f.Name.Name) { | |
561 | f.errorf(f.f, 1, link("http://golang.org/doc/effective_go.html#package-names"), category("mixed-caps"), "don't use MixedCaps in package name; %s should be %s", f.f.Name.Name, strings.ToLower(f.f.Name.Name)) | |
562 | } | |
540 | 563 | |
541 | 564 | check := func(id *ast.Ident, thing string) { |
542 | 565 | if id.Name == "_" { |
548 | 571 | |
549 | 572 | // Handle two common styles from other languages that don't belong in Go. |
550 | 573 | if len(id.Name) >= 5 && allCapsRE.MatchString(id.Name) && strings.Contains(id.Name, "_") { |
551 | f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use ALL_CAPS in Go names; use CamelCase") | |
552 | return | |
553 | } | |
554 | if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' { | |
555 | should := string(id.Name[1]+'a'-'A') + id.Name[2:] | |
556 | f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use leading k in Go names; %s %s should be %s", thing, id.Name, should) | |
574 | capCount := 0 | |
575 | for _, c := range id.Name { | |
576 | if 'A' <= c && c <= 'Z' { | |
577 | capCount++ | |
578 | } | |
579 | } | |
580 | if capCount >= 2 { | |
581 | f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use ALL_CAPS in Go names; use CamelCase") | |
582 | return | |
583 | } | |
584 | } | |
585 | if thing == "const" || (thing == "var" && isInTopLevel(f.f, id)) { | |
586 | if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' { | |
587 | should := string(id.Name[1]+'a'-'A') + id.Name[2:] | |
588 | f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use leading k in Go names; %s %s should be %s", thing, id.Name, should) | |
589 | } | |
557 | 590 | } |
558 | 591 | |
559 | 592 | should := lintName(id.Name) |
560 | 593 | if id.Name == should { |
561 | 594 | return |
562 | 595 | } |
596 | ||
563 | 597 | if len(id.Name) > 2 && strings.Contains(id.Name[1:], "_") { |
564 | 598 | f.errorf(id, 0.9, link("http://golang.org/doc/effective_go.html#mixed-caps"), category("naming"), "don't use underscores in Go names; %s %s should be %s", thing, id.Name, should) |
565 | 599 | return |
597 | 631 | thing = "method" |
598 | 632 | } |
599 | 633 | |
600 | check(v.Name, thing) | |
634 | // Exclude naming warnings for functions that are exported to C but | |
635 | // not exported in the Go API. | |
636 | // See https://github.com/golang/lint/issues/144. | |
637 | if ast.IsExported(v.Name.Name) || !isCgoExported(v) { | |
638 | check(v.Name, thing) | |
639 | } | |
601 | 640 | |
602 | 641 | checkList(v.Type.Params, thing+" parameter") |
603 | 642 | checkList(v.Type.Results, thing+" result") |
936 | 975 | "0i": true, |
937 | 976 | } |
938 | 977 | |
939 | // lintVarDecls examines variable declarations. It complains about declarations with | |
940 | // redundant LHS types that can be inferred from the RHS. | |
941 | func (f *file) lintVarDecls() { | |
942 | var lastGen *ast.GenDecl // last GenDecl entered. | |
943 | ||
944 | f.walk(func(node ast.Node) bool { | |
945 | switch v := node.(type) { | |
946 | case *ast.GenDecl: | |
947 | if v.Tok != token.CONST && v.Tok != token.VAR { | |
948 | return false | |
949 | } | |
950 | lastGen = v | |
951 | return true | |
952 | case *ast.ValueSpec: | |
953 | if lastGen.Tok == token.CONST { | |
954 | return false | |
955 | } | |
956 | if len(v.Names) > 1 || v.Type == nil || len(v.Values) == 0 { | |
957 | return false | |
958 | } | |
959 | rhs := v.Values[0] | |
960 | // An underscore var appears in a common idiom for compile-time interface satisfaction, | |
961 | // as in "var _ Interface = (*Concrete)(nil)". | |
962 | if isIdent(v.Names[0], "_") { | |
963 | return false | |
964 | } | |
965 | // If the RHS is a zero value, suggest dropping it. | |
966 | zero := false | |
967 | if lit, ok := rhs.(*ast.BasicLit); ok { | |
968 | zero = zeroLiteral[lit.Value] | |
969 | } else if isIdent(rhs, "nil") { | |
970 | zero = true | |
971 | } | |
972 | if zero { | |
973 | f.errorf(rhs, 0.9, category("zero-value"), "should drop = %s from declaration of var %s; it is the zero value", f.render(rhs), v.Names[0]) | |
974 | return false | |
975 | } | |
976 | lhsTyp := f.pkg.typeOf(v.Type) | |
977 | rhsTyp := f.pkg.typeOf(rhs) | |
978 | ||
979 | if !validType(lhsTyp) || !validType(rhsTyp) { | |
980 | // Type checking failed (often due to missing imports). | |
981 | return false | |
982 | } | |
983 | ||
984 | if !types.Identical(lhsTyp, rhsTyp) { | |
985 | // Assignment to a different type is not redundant. | |
986 | return false | |
987 | } | |
988 | ||
989 | // The next three conditions are for suppressing the warning in situations | |
990 | // where we were unable to typecheck. | |
991 | ||
992 | // If the LHS type is an interface, don't warn, since it is probably a | |
993 | // concrete type on the RHS. Note that our feeble lexical check here | |
994 | // will only pick up interface{} and other literal interface types; | |
995 | // that covers most of the cases we care to exclude right now. | |
996 | if _, ok := v.Type.(*ast.InterfaceType); ok { | |
997 | return false | |
998 | } | |
999 | // If the RHS is an untyped const, only warn if the LHS type is its default type. | |
1000 | if defType, ok := f.isUntypedConst(rhs); ok && !isIdent(v.Type, defType) { | |
1001 | return false | |
1002 | } | |
1003 | ||
1004 | f.errorf(v.Type, 0.8, category("type-inference"), "should omit type %s from declaration of var %s; it will be inferred from the right-hand side", f.render(v.Type), v.Names[0]) | |
1005 | return false | |
1006 | } | |
1007 | return true | |
1008 | }) | |
1009 | } | |
1010 | ||
1011 | func validType(T types.Type) bool { | |
1012 | return T != nil && | |
1013 | T != types.Typ[types.Invalid] && | |
1014 | !strings.Contains(T.String(), "invalid type") // good but not foolproof | |
1015 | } | |
1016 | ||
1017 | 978 | // lintElses examines else blocks. It complains about any else block whose if block ends in a return. |
1018 | 979 | func (f *file) lintElses() { |
1019 | 980 | // We don't want to flag if { } else if { } else { } constructions. |
1026 | 987 | if !ok || ifStmt.Else == nil { |
1027 | 988 | return true |
1028 | 989 | } |
1029 | if ignore[ifStmt] { | |
1030 | return true | |
1031 | } | |
1032 | 990 | if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok { |
1033 | 991 | ignore[elseif] = true |
992 | return true | |
993 | } | |
994 | if ignore[ifStmt] { | |
1034 | 995 | return true |
1035 | 996 | } |
1036 | 997 | if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok { |
1065 | 1026 | if !ok { |
1066 | 1027 | return true |
1067 | 1028 | } |
1068 | if rs.Value == nil { | |
1069 | // for x = range m { ... } | |
1070 | return true // single var form | |
1071 | } | |
1072 | if !isIdent(rs.Value, "_") { | |
1073 | // for ?, y = range m { ... } | |
1074 | return true | |
1075 | } | |
1076 | ||
1077 | p := f.errorf(rs.Value, 1, category("range-loop"), "should omit 2nd value from range; this loop is equivalent to `for %s %s range ...`", f.render(rs.Key), rs.Tok) | |
1078 | ||
1079 | newRS := *rs // shallow copy | |
1080 | newRS.Value = nil | |
1081 | p.ReplacementLine = f.firstLineOf(&newRS, rs) | |
1029 | ||
1030 | if isIdent(rs.Key, "_") && (rs.Value == nil || isIdent(rs.Value, "_")) { | |
1031 | p := f.errorf(rs.Key, 1, category("range-loop"), "should omit values from range; this loop is equivalent to `for range ...`") | |
1032 | ||
1033 | newRS := *rs // shallow copy | |
1034 | newRS.Value = nil | |
1035 | newRS.Key = nil | |
1036 | p.ReplacementLine = f.firstLineOf(&newRS, rs) | |
1037 | ||
1038 | return true | |
1039 | } | |
1040 | ||
1041 | if isIdent(rs.Value, "_") { | |
1042 | p := f.errorf(rs.Value, 1, category("range-loop"), "should omit 2nd value from range; this loop is equivalent to `for %s %s range ...`", f.render(rs.Key), rs.Tok) | |
1043 | ||
1044 | newRS := *rs // shallow copy | |
1045 | newRS.Value = nil | |
1046 | p.ReplacementLine = f.firstLineOf(&newRS, rs) | |
1047 | } | |
1082 | 1048 | |
1083 | 1049 | return true |
1084 | 1050 | }) |
1102 | 1068 | if !isErrorsNew && !isTestingError { |
1103 | 1069 | return true |
1104 | 1070 | } |
1071 | if !f.imports("errors") { | |
1072 | return true | |
1073 | } | |
1105 | 1074 | arg := ce.Args[0] |
1106 | 1075 | ce, ok = arg.(*ast.CallExpr) |
1107 | 1076 | if !ok || !isPkgDot(ce.Fun, "fmt", "Sprintf") { |
1154 | 1123 | } |
1155 | 1124 | } |
1156 | 1125 | |
1157 | func lintCapAndPunct(s string) (isCap, isPunct bool) { | |
1126 | func lintErrorString(s string) (isClean bool, conf float64) { | |
1127 | const basicConfidence = 0.8 | |
1128 | const capConfidence = basicConfidence - 0.2 | |
1158 | 1129 | first, firstN := utf8.DecodeRuneInString(s) |
1159 | 1130 | last, _ := utf8.DecodeLastRuneInString(s) |
1160 | isPunct = last == '.' || last == ':' || last == '!' | |
1161 | isCap = unicode.IsUpper(first) | |
1162 | if isCap && len(s) > firstN { | |
1163 | // Don't flag strings starting with something that looks like an initialism. | |
1164 | if second, _ := utf8.DecodeRuneInString(s[firstN:]); unicode.IsUpper(second) { | |
1165 | isCap = false | |
1166 | } | |
1167 | } | |
1168 | return | |
1169 | } | |
1170 | ||
1171 | // lintErrorStrings examines error strings. It complains if they are capitalized or end in punctuation. | |
1131 | if last == '.' || last == ':' || last == '!' || last == '\n' { | |
1132 | return false, basicConfidence | |
1133 | } | |
1134 | if unicode.IsUpper(first) { | |
1135 | // People use proper nouns and exported Go identifiers in error strings, | |
1136 | // so decrease the confidence of warnings for capitalization. | |
1137 | if len(s) <= firstN { | |
1138 | return false, capConfidence | |
1139 | } | |
1140 | // Flag strings starting with something that doesn't look like an initialism. | |
1141 | if second, _ := utf8.DecodeRuneInString(s[firstN:]); !unicode.IsUpper(second) { | |
1142 | return false, capConfidence | |
1143 | } | |
1144 | } | |
1145 | return true, 0 | |
1146 | } | |
1147 | ||
1148 | // lintErrorStrings examines error strings. | |
1149 | // It complains if they are capitalized or end in punctuation or a newline. | |
1172 | 1150 | func (f *file) lintErrorStrings() { |
1173 | 1151 | f.walk(func(node ast.Node) bool { |
1174 | 1152 | ce, ok := node.(*ast.CallExpr) |
1189 | 1167 | if s == "" { |
1190 | 1168 | return true |
1191 | 1169 | } |
1192 | isCap, isPunct := lintCapAndPunct(s) | |
1193 | var msg string | |
1194 | switch { | |
1195 | case isCap && isPunct: | |
1196 | msg = "error strings should not be capitalized and should not end with punctuation" | |
1197 | case isCap: | |
1198 | msg = "error strings should not be capitalized" | |
1199 | case isPunct: | |
1200 | msg = "error strings should not end with punctuation" | |
1201 | default: | |
1202 | return true | |
1203 | } | |
1204 | // People use proper nouns and exported Go identifiers in error strings, | |
1205 | // so decrease the confidence of warnings for capitalization. | |
1206 | conf := 0.8 | |
1207 | if isCap { | |
1208 | conf = 0.6 | |
1209 | } | |
1210 | f.errorf(str, conf, link(styleGuideBase+"#error-strings"), category("errors"), msg) | |
1170 | clean, conf := lintErrorString(s) | |
1171 | if clean { | |
1172 | return true | |
1173 | } | |
1174 | ||
1175 | f.errorf(str, conf, link(styleGuideBase+"#error-strings"), category("errors"), | |
1176 | "error strings should not be capitalized or end with punctuation or a newline") | |
1211 | 1177 | return true |
1212 | 1178 | }) |
1213 | 1179 | } |
1228 | 1194 | name := names[0].Name |
1229 | 1195 | const ref = styleGuideBase + "#receiver-names" |
1230 | 1196 | if name == "_" { |
1231 | f.errorf(n, 1, link(ref), category("naming"), `receiver name should not be an underscore`) | |
1197 | f.errorf(n, 1, link(ref), category("naming"), `receiver name should not be an underscore, omit the name if it is unused`) | |
1232 | 1198 | return true |
1233 | 1199 | } |
1234 | 1200 | if name == "this" || name == "self" { |
1283 | 1249 | } |
1284 | 1250 | ret := fn.Type.Results.List |
1285 | 1251 | if len(ret) <= 1 { |
1252 | return true | |
1253 | } | |
1254 | if isIdent(ret[len(ret)-1].Type, "error") { | |
1286 | 1255 | return true |
1287 | 1256 | } |
1288 | 1257 | // An error return parameter should be the last parameter. |
1431 | 1400 | } |
1432 | 1401 | key := f.pkg.typesInfo.Types[x.Args[1]] |
1433 | 1402 | |
1434 | if _, ok := key.Type.(*types.Basic); ok { | |
1403 | if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid { | |
1435 | 1404 | f.errorf(x, 1.0, category("context"), fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type)) |
1436 | 1405 | } |
1437 | 1406 | } |
1455 | 1424 | } |
1456 | 1425 | return true |
1457 | 1426 | }) |
1427 | } | |
1428 | ||
1429 | // containsComments returns whether the interval [start, end) contains any | |
1430 | // comments without "// MATCH " prefix. | |
1431 | func (f *file) containsComments(start, end token.Pos) bool { | |
1432 | for _, cgroup := range f.f.Comments { | |
1433 | comments := cgroup.List | |
1434 | if comments[0].Slash >= end { | |
1435 | // All comments starting with this group are after end pos. | |
1436 | return false | |
1437 | } | |
1438 | if comments[len(comments)-1].Slash < start { | |
1439 | // Comments group ends before start pos. | |
1440 | continue | |
1441 | } | |
1442 | for _, c := range comments { | |
1443 | if start <= c.Slash && c.Slash < end && !strings.HasPrefix(c.Text, "// MATCH ") { | |
1444 | return true | |
1445 | } | |
1446 | } | |
1447 | } | |
1448 | return false | |
1458 | 1449 | } |
1459 | 1450 | |
1460 | 1451 | // receiverType returns the named type of the method receiver, sans "*", |
1517 | 1508 | return ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name) |
1518 | 1509 | } |
1519 | 1510 | |
1520 | func isZero(expr ast.Expr) bool { | |
1521 | lit, ok := expr.(*ast.BasicLit) | |
1522 | return ok && lit.Kind == token.INT && lit.Value == "0" | |
1523 | } | |
1524 | ||
1525 | 1511 | func isOne(expr ast.Expr) bool { |
1526 | 1512 | lit, ok := expr.(*ast.BasicLit) |
1527 | 1513 | return ok && lit.Kind == token.INT && lit.Value == "1" |
1514 | } | |
1515 | ||
1516 | func isCgoExported(f *ast.FuncDecl) bool { | |
1517 | if f.Recv != nil || f.Doc == nil { | |
1518 | return false | |
1519 | } | |
1520 | ||
1521 | cgoExport := regexp.MustCompile(fmt.Sprintf("(?m)^//export %s$", regexp.QuoteMeta(f.Name.Name))) | |
1522 | for _, c := range f.Doc.List { | |
1523 | if cgoExport.MatchString(c.Text) { | |
1524 | return true | |
1525 | } | |
1526 | } | |
1527 | return false | |
1528 | 1528 | } |
1529 | 1529 | |
1530 | 1530 | var basicTypeKinds = map[types.BasicKind]string{ |
1585 | 1585 | return rx.FindStringSubmatch(line) |
1586 | 1586 | } |
1587 | 1587 | |
1588 | // imports returns true if the current file imports the specified package path. | |
1589 | func (f *file) imports(importPath string) bool { | |
1590 | all := astutil.Imports(f.fset, f.f) | |
1591 | for _, p := range all { | |
1592 | for _, i := range p { | |
1593 | uq, err := strconv.Unquote(i.Path.Value) | |
1594 | if err == nil && importPath == uq { | |
1595 | return true | |
1596 | } | |
1597 | } | |
1598 | } | |
1599 | return false | |
1600 | } | |
1601 | ||
1588 | 1602 | // srcLine returns the complete line at p, including the terminating newline. |
1589 | 1603 | func srcLine(src []byte, p token.Position) string { |
1590 | 1604 | // Run to end of line in both directions if not at line start/end. |
287 | 287 | } |
288 | 288 | } |
289 | 289 | } |
290 | ||
291 | func TestIsGenerated(t *testing.T) { | |
292 | tests := []struct { | |
293 | source string | |
294 | generated bool | |
295 | }{ | |
296 | {"// Code Generated by some tool. DO NOT EDIT.", false}, | |
297 | {"// Code generated by some tool. DO NOT EDIT.", true}, | |
298 | {"// Code generated by some tool. DO NOT EDIT", false}, | |
299 | {"// Code generated DO NOT EDIT.", true}, | |
300 | {"// Code generated DO NOT EDIT.", false}, | |
301 | {"\t\t// Code generated by some tool. DO NOT EDIT.\npackage foo\n", false}, | |
302 | {"// Code generated by some tool. DO NOT EDIT.\npackage foo\n", true}, | |
303 | {"package foo\n// Code generated by some tool. DO NOT EDIT.\ntype foo int\n", true}, | |
304 | {"package foo\n // Code generated by some tool. DO NOT EDIT.\ntype foo int\n", false}, | |
305 | {"package foo\n// Code generated by some tool. DO NOT EDIT. \ntype foo int\n", false}, | |
306 | {"package foo\ntype foo int\n// Code generated by some tool. DO NOT EDIT.\n", true}, | |
307 | {"package foo\ntype foo int\n// Code generated by some tool. DO NOT EDIT.", true}, | |
308 | } | |
309 | ||
310 | for i, test := range tests { | |
311 | got := isGenerated([]byte(test.source)) | |
312 | if got != test.generated { | |
313 | t.Errorf("test %d, isGenerated() = %v, want %v", i, got, test.generated) | |
314 | } | |
315 | } | |
316 | } |
0 | 0 | ;;; golint.el --- lint for the Go source code |
1 | 1 | |
2 | 2 | ;; Copyright 2013 The Go Authors. All rights reserved. |
3 | ;; Use of this source code is governed by a BSD-style | |
4 | ;; license that can be found in the LICENSE file. | |
5 | 3 | |
4 | ;; License: BSD-3-clause | |
6 | 5 | ;; URL: https://github.com/golang/lint |
7 | 6 | |
8 | 7 | ;;; Commentary: |
16 | 15 | ;; Usage: |
17 | 16 | ;; C-x ` |
18 | 17 | ;; Jump directly to the line in your code which caused the first message. |
19 | ;; | |
18 | ;; | |
20 | 19 | ;; For more usage, see Compilation-Mode: |
21 | 20 | ;; http://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html |
22 | 21 | |
23 | 22 | ;;; Code: |
23 | ||
24 | 24 | (require 'compile) |
25 | 25 | |
26 | (defun go-lint-buffer-name (mode) | |
27 | "*Golint*") | |
26 | (defun go-lint-buffer-name (mode) | |
27 | "*Golint*") | |
28 | 28 | |
29 | 29 | (defun golint-process-setup () |
30 | 30 | "Setup compilation variables and buffer for `golint'." |
35 | 35 | (set (make-local-variable 'compilation-scroll-output) nil) |
36 | 36 | (set (make-local-variable 'compilation-disable-input) t) |
37 | 37 | (set (make-local-variable 'compilation-process-setup-function) |
38 | 'golint-process-setup) | |
39 | ) | |
38 | 'golint-process-setup)) | |
40 | 39 | |
41 | 40 | ;;;###autoload |
42 | 41 | (defun golint () |
43 | "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." | |
42 | "Run golint on the current file and populate the fix list. | |
43 | Pressing \"C-x `\" jumps directly to the line in your code which | |
44 | caused the first message." | |
44 | 45 | (interactive) |
45 | 46 | (compilation-start |
46 | 47 | (mapconcat #'shell-quote-argument |
33 | 33 | context.WithValue(c, complex128(1i), "bar") // MATCH /should not use basic type complex128 as key in context.WithValue/ |
34 | 34 | context.WithValue(c, ctxKey{}, "bar") // ok |
35 | 35 | context.WithValue(c, &ctxKey{}, "bar") // ok |
36 | context.WithValue(c, invalid{}, "bar") // ok | |
36 | 37 | } |
15 | 15 | } |
16 | 16 | return false |
17 | 17 | } |
18 | ||
19 | func g(x int) int { | |
20 | if x == 0 { | |
21 | log.Print("x is zero") | |
22 | } else if x > 9 { | |
23 | return 2 | |
24 | } else if x > 0 { | |
25 | return 1 | |
26 | } else { | |
27 | log.Printf("non-positive x: %d", x) | |
28 | } | |
29 | return 0 | |
30 | } | |
31 | ||
32 | func h(x int) int { | |
33 | if x == 0 { | |
34 | log.Print("x is zero") | |
35 | } else if x > 99 { | |
36 | return 3 | |
37 | } else if x > 9 { | |
38 | return 2 | |
39 | } else if x > 0 { | |
40 | return 1 | |
41 | } else { | |
42 | log.Printf("non-positive x: %d", x) | |
43 | } | |
44 | return 0 | |
45 | } |
40 | 40 | func m() (x int, err error, y int) { // MATCH /error should be the last type/ |
41 | 41 | return 0, nil, 0 |
42 | 42 | } |
43 | ||
44 | // Check for multiple error returns but with errors at the end. | |
45 | func n() (int, error, error) { // OK | |
46 | return 0, nil, nil | |
47 | } | |
48 | ||
49 | // Check for multiple error returns mixed in order, but keeping one error at last position. | |
50 | func o() (int, error, int, error) { // OK | |
51 | return 0, nil, 0, nil | |
52 | } |
0 | // Test for allowed errors.New(fmt.Sprintf()) when a custom errors package is imported. | |
1 | ||
2 | // Package foo ... | |
3 | package foo | |
4 | ||
5 | import ( | |
6 | "fmt" | |
7 | ||
8 | "github.com/pkg/errors" | |
9 | ) | |
10 | ||
11 | func f(x int) error { | |
12 | if x > 10 { | |
13 | return errors.New(fmt.Sprintf("something %d", x)) // OK | |
14 | } | |
15 | if x > 5 { | |
16 | return errors.New(g("blah")) // OK | |
17 | } | |
18 | if x > 4 { | |
19 | return errors.New("something else") // OK | |
20 | } | |
21 | return nil | |
22 | } | |
23 | ||
24 | func g(s string) string { return "prefix: " + s } |
26 | 26 | // Check for the error strings themselves. |
27 | 27 | |
28 | 28 | func g(x int) error { |
29 | if x < 1 { | |
30 | return fmt.Errorf("This %d is too low", x) // MATCH /error strings.*not be capitalized/ | |
31 | } else if x == 0 { | |
32 | return fmt.Errorf("XML time") // ok | |
33 | } | |
34 | return errors.New(`too much stuff.`) // MATCH /error strings.*not end with punctuation/ | |
29 | var err error | |
30 | err = fmt.Errorf("This %d is too low", x) // MATCH /error strings.*be capitalized/ | |
31 | err = fmt.Errorf("XML time") // ok | |
32 | err = fmt.Errorf("newlines are fun\n") // MATCH /error strings.*end with punctuation/ | |
33 | err = fmt.Errorf("Newlines are really fun\n") // MATCH /error strings.+not be capitalized/ | |
34 | err = errors.New(`too much stuff.`) // MATCH /error strings.*end with punctuation/ | |
35 | err = errors.New("This %d is too low", x) // MATCH /error strings.*be capitalized/ | |
36 | return err | |
35 | 37 | } |
8 | 8 | net_http "net/http" // renamed deliberately |
9 | 9 | "net/url" |
10 | 10 | ) |
11 | ||
12 | import "C" | |
11 | 13 | |
12 | 14 | var var_name int // MATCH /underscore.*var.*var_name/ |
13 | 15 | |
56 | 58 | CPP_CONST = 1 // MATCH /ALL_CAPS.*CamelCase/ |
57 | 59 | kLeadingKay = 2 // MATCH /k.*leadingKay/ |
58 | 60 | |
59 | HTML = 3 // okay; no underscore | |
60 | X509B = 4 // ditto | |
61 | HTML = 3 // okay; no underscore | |
62 | X509B = 4 // ditto | |
63 | V1_10_5 = 5 // okay; fewer than two uppercase letters | |
61 | 64 | ) |
65 | ||
66 | var kVarsAreSometimesUsedAsConstants = 0 // MATCH /k.*varsAreSometimesUsedAsConstants/ | |
67 | var ( | |
68 | kVarsAreSometimesUsedAsConstants2 = 0 // MATCH /k.*varsAreSometimesUsedAsConstants2/ | |
69 | ) | |
70 | ||
71 | var kThisIsNotOkay = struct { // MATCH /k.*thisIsNotOkay/ | |
72 | kThisIsOkay bool | |
73 | }{} | |
74 | ||
75 | func kThisIsOkay() { // this is okay because this is a function name | |
76 | var kThisIsAlsoOkay = 1 // this is okay because this is a non-top-level variable | |
77 | _ = kThisIsAlsoOkay | |
78 | const kThisIsNotOkay = 2 // MATCH /k.*thisIsNotOkay/ | |
79 | } | |
80 | ||
81 | var anotherFunctionScope = func() { | |
82 | var kThisIsOkay = 1 // this is okay because this is a non-top-level variable | |
83 | _ = kThisIsOkay | |
84 | const kThisIsNotOkay = 2 // MATCH /k.*thisIsNotOkay/} | |
85 | } | |
62 | 86 | |
63 | 87 | func f(bad_name int) {} // MATCH /underscore.*func parameter.*bad_name/ |
64 | 88 | func g() (no_way int) { return 0 } // MATCH /underscore.*func result.*no_way/ |
88 | 112 | type t struct{} |
89 | 113 | |
90 | 114 | func (t) LastInsertId() (int64, error) { return 0, nil } // okay because it matches a known style violation |
115 | ||
116 | //export exported_to_c | |
117 | func exported_to_c() {} // okay: https://github.com/golang/lint/issues/144 | |
118 | ||
119 | //export exported_to_c_with_arg | |
120 | func exported_to_c_with_arg(but_use_go_param_names int) // MATCH /underscore.*func parameter.*but_use_go_param_names/ | |
121 | ||
122 | // This is an exported C function with a leading doc comment. | |
123 | // | |
124 | //export exported_to_c_with_comment | |
125 | func exported_to_c_with_comment() {} // okay: https://github.com/golang/lint/issues/144 | |
126 | ||
127 | //export maybe_exported_to_CPlusPlusWithCamelCase | |
128 | func maybe_exported_to_CPlusPlusWithCamelCase() {} // okay: https://github.com/golang/lint/issues/144 | |
129 | ||
130 | // WhyAreYouUsingCapitalLetters_InACFunctionName is a Go-exported function that | |
131 | // is also exported to C as a name with underscores. | |
132 | // | |
133 | // Don't do that. If you want to use a C-style name for a C export, make it | |
134 | // lower-case and leave it out of the Go-exported API. | |
135 | // | |
136 | //export WhyAreYouUsingCapitalLetters_InACFunctionName | |
137 | func WhyAreYouUsingCapitalLetters_InACFunctionName() {} // MATCH /underscore.*func.*Why.*CFunctionName/ |
0 | // MixedCaps package name | |
1 | ||
2 | // Package PkgName ... | |
3 | package PkgName // MATCH /don't use MixedCaps in package name/ |
13 | 13 | var y string |
14 | 14 | _ = y |
15 | 15 | for y, _ = range m { // MATCH /should omit 2nd value.*range.*equivalent.*for y = range/ |
16 | } | |
17 | ||
18 | for _ = range m { // MATCH /should omit values.*range.*equivalent.*for range/ | |
19 | } | |
20 | ||
21 | for _, _ = range m { // MATCH /should omit values.*range.*equivalent.*for range/ | |
16 | 22 | } |
17 | 23 | |
18 | 24 | // all OK: |
0 | // Test for redundant type declaration. | |
1 | ||
2 | // Package foo ... | |
3 | package foo | |
4 | ||
5 | import ( | |
6 | "fmt" | |
7 | "io" | |
8 | "net/http" | |
9 | "nosuchpkg" // export data unavailable | |
10 | "os" | |
11 | ) | |
12 | ||
13 | // Q is a test type. | |
14 | type Q bool | |
15 | ||
16 | var myInt int = 7 // MATCH /should.*int.*myInt.*inferred/ | |
17 | var mux *http.ServeMux = http.NewServeMux() // MATCH /should.*\*http\.ServeMux.*inferred/ | |
18 | ||
19 | var myZeroInt int = 0 // MATCH /should.*= 0.*myZeroInt.*zero value/ | |
20 | var myZeroFlt float32 = 0. // MATCH /should.*= 0\..*myZeroFlt.*zero value/ | |
21 | var myZeroF64 float64 = 0.0 // MATCH /should.*= 0\..*myZeroF64.*zero value/ | |
22 | var myZeroImg complex64 = 0i // MATCH /should.*= 0i.*myZeroImg.*zero value/ | |
23 | var myZeroStr string = "" // MATCH /should.*= "".*myZeroStr.*zero value/ | |
24 | var myZeroRaw string = `` // MATCH /should.*= ``.*myZeroRaw.*zero value/ | |
25 | var myZeroPtr *Q = nil // MATCH /should.*= nil.*myZeroPtr.*zero value/ | |
26 | var myZeroRune rune = '\x00' // MATCH /should.*= '\\x00'.*myZeroRune.*zero value/ | |
27 | var myZeroRune2 rune = '\000' // MATCH /should.*= '\\000'.*myZeroRune2.*zero value/ | |
28 | ||
29 | // No warning because there's no type on the LHS | |
30 | var x = 0 | |
31 | ||
32 | // This shouldn't get a warning because there's no initial values. | |
33 | var str fmt.Stringer | |
34 | ||
35 | // No warning because this is a const. | |
36 | const k uint64 = 7 | |
37 | ||
38 | const num = 123 | |
39 | ||
40 | // No warning because the var's RHS is known to be an untyped const. | |
41 | var flags uint32 = num | |
42 | ||
43 | // No warnings because the RHS is an ideal int, and the LHS is a different int type. | |
44 | var userID int64 = 1235 | |
45 | var negID int64 = -1 | |
46 | var parenID int64 = (17) | |
47 | var crazyID int64 = -(-(-(-9))) | |
48 | ||
49 | // Same, but for strings and floats. | |
50 | type stringT string | |
51 | type floatT float64 | |
52 | ||
53 | var stringV stringT = "abc" | |
54 | var floatV floatT = 123.45 | |
55 | ||
56 | // No warning because the LHS names an interface type. | |
57 | var data interface{} = googleIPs | |
58 | var googleIPs []int | |
59 | ||
60 | // No warning because it's a common idiom for interface satisfaction. | |
61 | var _ Server = (*serverImpl)(nil) | |
62 | ||
63 | // Server is a test type. | |
64 | type Server interface{} | |
65 | type serverImpl struct{} | |
66 | ||
67 | // LHS is a different type than the RHS. | |
68 | var myStringer fmt.Stringer = q(0) | |
69 | ||
70 | // LHS is a different type than the RHS. | |
71 | var out io.Writer = os.Stdout | |
72 | ||
73 | var out2 io.Writer = newWriter() // MATCH /should omit.*io\.Writer/ | |
74 | ||
75 | func newWriter() io.Writer { return nil } | |
76 | ||
77 | // We don't figure out the true types of LHS and RHS here, | |
78 | // so we suppress the check. | |
79 | var ni nosuchpkg.Interface = nosuchpkg.NewConcrete() | |
80 | ||
81 | var y string = q(1).String() // MATCH /should.*string/ | |
82 | ||
83 | type q int | |
84 | ||
85 | func (q) String() string { return "I'm a q" } |