github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/lint/lint.go (about)

     1  // Copyright (c) 2013 The Go Authors. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file or at
     5  // https://developers.google.com/open-source/licenses/bsd.
     6  
     7  // Package lint contains a linter for Go source code.
     8  package lint
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	"go/ast"
    14  	"go/parser"
    15  	"go/printer"
    16  	"go/token"
    17  	"regexp"
    18  	"sort"
    19  	"strconv"
    20  	"strings"
    21  	"unicode"
    22  	"unicode/utf8"
    23  
    24  	"github.com/insionng/yougam/libraries/x/tools/go/gcimporter"
    25  	"github.com/insionng/yougam/libraries/x/tools/go/types"
    26  )
    27  
    28  const styleGuideBase = "https://yougam/libraries/wiki/CodeReviewComments"
    29  
    30  // A Linter lints Go source code.
    31  type Linter struct {
    32  }
    33  
    34  // Problem represents a problem in some source code.
    35  type Problem struct {
    36  	Position   token.Position // position in source file
    37  	Text       string         // the prose that describes the problem
    38  	Link       string         // (optional) the link to the style guide for the problem
    39  	Confidence float64        // a value in (0,1] estimating the confidence in this problem's correctness
    40  	LineText   string         // the source line
    41  	Category   string         // a short name for the general category of the problem
    42  
    43  	// If the problem has a suggested fix (the minority case),
    44  	// ReplacementLine is a full replacement for the relevant line of the source file.
    45  	ReplacementLine string
    46  }
    47  
    48  func (p *Problem) String() string {
    49  	if p.Link != "" {
    50  		return p.Text + "\n\n" + p.Link
    51  	}
    52  	return p.Text
    53  }
    54  
    55  type byPosition []Problem
    56  
    57  func (p byPosition) Len() int      { return len(p) }
    58  func (p byPosition) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
    59  
    60  func (p byPosition) Less(i, j int) bool {
    61  	pi, pj := p[i].Position, p[j].Position
    62  
    63  	if pi.Filename != pj.Filename {
    64  		return pi.Filename < pj.Filename
    65  	}
    66  	if pi.Line != pj.Line {
    67  		return pi.Line < pj.Line
    68  	}
    69  	if pi.Column != pj.Column {
    70  		return pi.Column < pj.Column
    71  	}
    72  
    73  	return p[i].Text < p[j].Text
    74  }
    75  
    76  // Lint lints src.
    77  func (l *Linter) Lint(filename string, src []byte) ([]Problem, error) {
    78  	return l.LintFiles(map[string][]byte{filename: src})
    79  }
    80  
    81  // LintFiles lints a set of files of a single package.
    82  // The argument is a map of filename to source.
    83  func (l *Linter) LintFiles(files map[string][]byte) ([]Problem, error) {
    84  	if len(files) == 0 {
    85  		return nil, nil
    86  	}
    87  	pkg := &pkg{
    88  		fset:  token.NewFileSet(),
    89  		files: make(map[string]*file),
    90  	}
    91  	var pkgName string
    92  	for filename, src := range files {
    93  		f, err := parser.ParseFile(pkg.fset, filename, src, parser.ParseComments)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  		if pkgName == "" {
    98  			pkgName = f.Name.Name
    99  		} else if f.Name.Name != pkgName {
   100  			return nil, fmt.Errorf("%s is in package %s, not %s", filename, f.Name.Name, pkgName)
   101  		}
   102  		pkg.files[filename] = &file{
   103  			pkg:      pkg,
   104  			f:        f,
   105  			fset:     pkg.fset,
   106  			src:      src,
   107  			filename: filename,
   108  		}
   109  	}
   110  	return pkg.lint(), nil
   111  }
   112  
   113  // pkg represents a package being linted.
   114  type pkg struct {
   115  	fset  *token.FileSet
   116  	files map[string]*file
   117  
   118  	typesPkg  *types.Package
   119  	typesInfo *types.Info
   120  
   121  	// sortable is the set of types in the package that implement sort.Interface.
   122  	sortable map[string]bool
   123  	// main is whether this is a "main" package.
   124  	main bool
   125  
   126  	problems []Problem
   127  }
   128  
   129  func (p *pkg) lint() []Problem {
   130  	if err := p.typeCheck(); err != nil {
   131  		/* TODO(dsymonds): Consider reporting these errors when golint operates on entire packages.
   132  		if e, ok := err.(types.Error); ok {
   133  			pos := p.fset.Position(e.Pos)
   134  			conf := 1.0
   135  			if strings.Contains(e.Msg, "can't find import: ") {
   136  				// Golint is probably being run in a context that doesn't support
   137  				// typechecking (e.g. package files aren't found), so don't warn about it.
   138  				conf = 0
   139  			}
   140  			if conf > 0 {
   141  				p.errorfAt(pos, conf, category("typechecking"), e.Msg)
   142  			}
   143  
   144  			// TODO(dsymonds): Abort if !e.Soft?
   145  		}
   146  		*/
   147  	}
   148  
   149  	p.scanSortable()
   150  	p.main = p.isMain()
   151  
   152  	for _, f := range p.files {
   153  		f.lint()
   154  	}
   155  
   156  	sort.Sort(byPosition(p.problems))
   157  
   158  	return p.problems
   159  }
   160  
   161  // file represents a file being linted.
   162  type file struct {
   163  	pkg      *pkg
   164  	f        *ast.File
   165  	fset     *token.FileSet
   166  	src      []byte
   167  	filename string
   168  }
   169  
   170  func (f *file) isTest() bool { return strings.HasSuffix(f.filename, "_test.go") }
   171  
   172  func (f *file) lint() {
   173  	f.lintPackageComment()
   174  	f.lintImports()
   175  	f.lintBlankImports()
   176  	f.lintExported()
   177  	f.lintNames()
   178  	f.lintVarDecls()
   179  	f.lintElses()
   180  	f.lintRanges()
   181  	f.lintErrorf()
   182  	f.lintErrors()
   183  	f.lintErrorStrings()
   184  	f.lintReceiverNames()
   185  	f.lintIncDec()
   186  	f.lintMake()
   187  	f.lintErrorReturn()
   188  	f.lintUnexportedReturn()
   189  	f.lintTimeNames()
   190  }
   191  
   192  type link string
   193  type category string
   194  
   195  // The variadic arguments may start with link and category types,
   196  // and must end with a format string and any arguments.
   197  // It returns the new Problem.
   198  func (f *file) errorf(n ast.Node, confidence float64, args ...interface{}) *Problem {
   199  	pos := f.fset.Position(n.Pos())
   200  	if pos.Filename == "" {
   201  		pos.Filename = f.filename
   202  	}
   203  	return f.pkg.errorfAt(pos, confidence, args...)
   204  }
   205  
   206  func (p *pkg) errorfAt(pos token.Position, confidence float64, args ...interface{}) *Problem {
   207  	problem := Problem{
   208  		Position:   pos,
   209  		Confidence: confidence,
   210  	}
   211  	if pos.Filename != "" {
   212  		// The file might not exist in our mapping if a //line directive was encountered.
   213  		if f, ok := p.files[pos.Filename]; ok {
   214  			problem.LineText = srcLine(f.src, pos)
   215  		}
   216  	}
   217  
   218  argLoop:
   219  	for len(args) > 1 { // always leave at least the format string in args
   220  		switch v := args[0].(type) {
   221  		case link:
   222  			problem.Link = string(v)
   223  		case category:
   224  			problem.Category = string(v)
   225  		default:
   226  			break argLoop
   227  		}
   228  		args = args[1:]
   229  	}
   230  
   231  	problem.Text = fmt.Sprintf(args[0].(string), args[1:]...)
   232  
   233  	p.problems = append(p.problems, problem)
   234  	return &p.problems[len(p.problems)-1]
   235  }
   236  
   237  var gcImporter = gcimporter.Import
   238  
   239  func (p *pkg) typeCheck() error {
   240  	config := &types.Config{
   241  		// By setting a no-op error reporter, the type checker does as much work as possible.
   242  		Error:  func(error) {},
   243  		Import: gcImporter,
   244  	}
   245  	info := &types.Info{
   246  		Types:  make(map[ast.Expr]types.TypeAndValue),
   247  		Defs:   make(map[*ast.Ident]types.Object),
   248  		Uses:   make(map[*ast.Ident]types.Object),
   249  		Scopes: make(map[ast.Node]*types.Scope),
   250  	}
   251  	var anyFile *file
   252  	var astFiles []*ast.File
   253  	for _, f := range p.files {
   254  		anyFile = f
   255  		astFiles = append(astFiles, f.f)
   256  	}
   257  	pkg, err := config.Check(anyFile.f.Name.Name, p.fset, astFiles, info)
   258  	// Remember the typechecking info, even if config.Check failed,
   259  	// since we will get partial information.
   260  	p.typesPkg = pkg
   261  	p.typesInfo = info
   262  	return err
   263  }
   264  
   265  func (p *pkg) typeOf(expr ast.Expr) types.Type {
   266  	if p.typesInfo == nil {
   267  		return nil
   268  	}
   269  	return p.typesInfo.TypeOf(expr)
   270  }
   271  
   272  func (p *pkg) isNamedType(typ types.Type, importPath, name string) bool {
   273  	n, ok := typ.(*types.Named)
   274  	if !ok {
   275  		return false
   276  	}
   277  	tn := n.Obj()
   278  	return tn != nil && tn.Pkg() != nil && tn.Pkg().Path() == importPath && tn.Name() == name
   279  }
   280  
   281  // scopeOf returns the tightest scope encompassing id.
   282  func (p *pkg) scopeOf(id *ast.Ident) *types.Scope {
   283  	var scope *types.Scope
   284  	if obj := p.typesInfo.ObjectOf(id); obj != nil {
   285  		scope = obj.Parent()
   286  	}
   287  	if scope == p.typesPkg.Scope() {
   288  		// We were given a top-level identifier.
   289  		// Use the file-level scope instead of the package-level scope.
   290  		pos := id.Pos()
   291  		for _, f := range p.files {
   292  			if f.f.Pos() <= pos && pos < f.f.End() {
   293  				scope = p.typesInfo.Scopes[f.f]
   294  				break
   295  			}
   296  		}
   297  	}
   298  	return scope
   299  }
   300  
   301  func (p *pkg) scanSortable() {
   302  	p.sortable = make(map[string]bool)
   303  
   304  	// bitfield for which methods exist on each type.
   305  	const (
   306  		Len = 1 << iota
   307  		Less
   308  		Swap
   309  	)
   310  	nmap := map[string]int{"Len": Len, "Less": Less, "Swap": Swap}
   311  	has := make(map[string]int)
   312  	for _, f := range p.files {
   313  		f.walk(func(n ast.Node) bool {
   314  			fn, ok := n.(*ast.FuncDecl)
   315  			if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 {
   316  				return true
   317  			}
   318  			// TODO(dsymonds): We could check the signature to be more precise.
   319  			recv := receiverType(fn)
   320  			if i, ok := nmap[fn.Name.Name]; ok {
   321  				has[recv] |= i
   322  			}
   323  			return false
   324  		})
   325  	}
   326  	for typ, ms := range has {
   327  		if ms == Len|Less|Swap {
   328  			p.sortable[typ] = true
   329  		}
   330  	}
   331  }
   332  
   333  func (p *pkg) isMain() bool {
   334  	for _, f := range p.files {
   335  		if f.isMain() {
   336  			return true
   337  		}
   338  	}
   339  	return false
   340  }
   341  
   342  func (f *file) isMain() bool {
   343  	if f.f.Name.Name == "main" {
   344  		return true
   345  	}
   346  	return false
   347  }
   348  
   349  // lintPackageComment checks package comments. It complains if
   350  // there is no package comment, or if it is not of the right form.
   351  // This has a notable false positive in that a package comment
   352  // could rightfully appear in a different file of the same package,
   353  // but that's not easy to fix since this linter is file-oriented.
   354  func (f *file) lintPackageComment() {
   355  	if f.isTest() {
   356  		return
   357  	}
   358  
   359  	const ref = styleGuideBase + "#package-comments"
   360  	prefix := "Package " + f.f.Name.Name + " "
   361  
   362  	// Look for a detached package comment.
   363  	// First, scan for the last comment that occurs before the "package" keyword.
   364  	var lastCG *ast.CommentGroup
   365  	for _, cg := range f.f.Comments {
   366  		if cg.Pos() > f.f.Package {
   367  			// Gone past "package" keyword.
   368  			break
   369  		}
   370  		lastCG = cg
   371  	}
   372  	if lastCG != nil && strings.HasPrefix(lastCG.Text(), prefix) {
   373  		endPos := f.fset.Position(lastCG.End())
   374  		pkgPos := f.fset.Position(f.f.Package)
   375  		if endPos.Line+1 < pkgPos.Line {
   376  			// There isn't a great place to anchor this error;
   377  			// the start of the blank lines between the doc and the package statement
   378  			// is at least pointing at the location of the problem.
   379  			pos := token.Position{
   380  				Filename: endPos.Filename,
   381  				// Offset not set; it is non-trivial, and doesn't appear to be needed.
   382  				Line:   endPos.Line + 1,
   383  				Column: 1,
   384  			}
   385  			f.pkg.errorfAt(pos, 0.9, link(ref), category("comments"), "package comment is detached; there should be no blank lines between it and the package statement")
   386  			return
   387  		}
   388  	}
   389  
   390  	if f.f.Doc == nil {
   391  		f.errorf(f.f, 0.2, link(ref), category("comments"), "should have a package comment, unless it's in another file for this package")
   392  		return
   393  	}
   394  	s := f.f.Doc.Text()
   395  	if ts := strings.TrimLeft(s, " \t"); ts != s {
   396  		f.errorf(f.f.Doc, 1, link(ref), category("comments"), "package comment should not have leading space")
   397  		s = ts
   398  	}
   399  	// Only non-main packages need to keep to this form.
   400  	if f.f.Name.Name != "main" && !strings.HasPrefix(s, prefix) {
   401  		f.errorf(f.f.Doc, 1, link(ref), category("comments"), `package comment should be of the form "%s..."`, prefix)
   402  	}
   403  }
   404  
   405  // lintBlankImports complains if a non-main package has blank imports that are
   406  // not documented.
   407  func (f *file) lintBlankImports() {
   408  	// In package main and in tests, we don't complain about blank imports.
   409  	if f.pkg.main || f.isTest() {
   410  		return
   411  	}
   412  
   413  	// The first element of each contiguous group of blank imports should have
   414  	// an explanatory comment of some kind.
   415  	for i, imp := range f.f.Imports {
   416  		pos := f.fset.Position(imp.Pos())
   417  
   418  		if !isBlank(imp.Name) {
   419  			continue // Ignore non-blank imports.
   420  		}
   421  		if i > 0 {
   422  			prev := f.f.Imports[i-1]
   423  			prevPos := f.fset.Position(prev.Pos())
   424  			if isBlank(prev.Name) && prevPos.Line+1 == pos.Line {
   425  				continue // A subsequent blank in a group.
   426  			}
   427  		}
   428  
   429  		// This is the first blank import of a group.
   430  		if imp.Doc == nil && imp.Comment == nil {
   431  			ref := ""
   432  			f.errorf(imp, 1, link(ref), category("imports"), "a blank import should be only in a main or test package, or have a comment justifying it")
   433  		}
   434  	}
   435  }
   436  
   437  // lintImports examines import blocks.
   438  func (f *file) lintImports() {
   439  
   440  	for i, is := range f.f.Imports {
   441  		_ = i
   442  		if is.Name != nil && is.Name.Name == "." && !f.isTest() {
   443  			f.errorf(is, 1, link(styleGuideBase+"#import-dot"), category("imports"), "should not use dot imports")
   444  		}
   445  
   446  	}
   447  
   448  }
   449  
   450  const docCommentsLink = styleGuideBase + "#doc-comments"
   451  
   452  // lintExported examines the exported names.
   453  // It complains if any required doc comments are missing,
   454  // or if they are not of the right form. The exact rules are in
   455  // lintFuncDoc, lintTypeDoc and lintValueSpecDoc; this function
   456  // also tracks the GenDecl structure being traversed to permit
   457  // doc comments for constants to be on top of the const block.
   458  // It also complains if the names stutter when combined with
   459  // the package name.
   460  func (f *file) lintExported() {
   461  	if f.isTest() {
   462  		return
   463  	}
   464  
   465  	var lastGen *ast.GenDecl // last GenDecl entered.
   466  
   467  	// Set of GenDecls that have already had missing comments flagged.
   468  	genDeclMissingComments := make(map[*ast.GenDecl]bool)
   469  
   470  	f.walk(func(node ast.Node) bool {
   471  		switch v := node.(type) {
   472  		case *ast.GenDecl:
   473  			if v.Tok == token.IMPORT {
   474  				return false
   475  			}
   476  			// token.CONST, token.TYPE or token.VAR
   477  			lastGen = v
   478  			return true
   479  		case *ast.FuncDecl:
   480  			f.lintFuncDoc(v)
   481  			if v.Recv == nil {
   482  				// Only check for stutter on functions, not methods.
   483  				// Method names are not used package-qualified.
   484  				f.checkStutter(v.Name, "func")
   485  			}
   486  			// Don't proceed inside funcs.
   487  			return false
   488  		case *ast.TypeSpec:
   489  			// inside a GenDecl, which usually has the doc
   490  			doc := v.Doc
   491  			if doc == nil {
   492  				doc = lastGen.Doc
   493  			}
   494  			f.lintTypeDoc(v, doc)
   495  			f.checkStutter(v.Name, "type")
   496  			// Don't proceed inside types.
   497  			return false
   498  		case *ast.ValueSpec:
   499  			f.lintValueSpecDoc(v, lastGen, genDeclMissingComments)
   500  			return false
   501  		}
   502  		return true
   503  	})
   504  }
   505  
   506  var allCapsRE = regexp.MustCompile(`^[A-Z0-9_]+$`)
   507  
   508  // lintNames examines all names in the file.
   509  // It complains if any use underscores or incorrect known initialisms.
   510  func (f *file) lintNames() {
   511  	// Package names need slightly different handling than other names.
   512  	if strings.Contains(f.f.Name.Name, "_") && !strings.HasSuffix(f.f.Name.Name, "_test") {
   513  		f.errorf(f.f, 1, link("http://yougam/libraries/doc/effective_go.html#package-names"), category("naming"), "don't use an underscore in package name")
   514  	}
   515  
   516  	check := func(id *ast.Ident, thing string) {
   517  		if id.Name == "_" {
   518  			return
   519  		}
   520  
   521  		// Handle two common styles from other languages that don't belong in Go.
   522  		if len(id.Name) >= 5 && allCapsRE.MatchString(id.Name) && strings.Contains(id.Name, "_") {
   523  			f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use ALL_CAPS in Go names; use CamelCase")
   524  			return
   525  		}
   526  		if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' {
   527  			should := string(id.Name[1]+'a'-'A') + id.Name[2:]
   528  			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)
   529  		}
   530  
   531  		should := lintName(id.Name)
   532  		if id.Name == should {
   533  			return
   534  		}
   535  		if len(id.Name) > 2 && strings.Contains(id.Name[1:], "_") {
   536  			f.errorf(id, 0.9, link("http://yougam/libraries/doc/effective_go.html#mixed-caps"), category("naming"), "don't use underscores in Go names; %s %s should be %s", thing, id.Name, should)
   537  			return
   538  		}
   539  		f.errorf(id, 0.8, link(styleGuideBase+"#initialisms"), category("naming"), "%s %s should be %s", thing, id.Name, should)
   540  	}
   541  	checkList := func(fl *ast.FieldList, thing string) {
   542  		if fl == nil {
   543  			return
   544  		}
   545  		for _, f := range fl.List {
   546  			for _, id := range f.Names {
   547  				check(id, thing)
   548  			}
   549  		}
   550  	}
   551  	f.walk(func(node ast.Node) bool {
   552  		switch v := node.(type) {
   553  		case *ast.AssignStmt:
   554  			if v.Tok == token.ASSIGN {
   555  				return true
   556  			}
   557  			for _, exp := range v.Lhs {
   558  				if id, ok := exp.(*ast.Ident); ok {
   559  					check(id, "var")
   560  				}
   561  			}
   562  		case *ast.FuncDecl:
   563  			if f.isTest() && (strings.HasPrefix(v.Name.Name, "Example") || strings.HasPrefix(v.Name.Name, "Test") || strings.HasPrefix(v.Name.Name, "Benchmark")) {
   564  				return true
   565  			}
   566  
   567  			thing := "func"
   568  			if v.Recv != nil {
   569  				thing = "method"
   570  			}
   571  
   572  			check(v.Name, thing)
   573  
   574  			checkList(v.Type.Params, thing+" parameter")
   575  			checkList(v.Type.Results, thing+" result")
   576  		case *ast.GenDecl:
   577  			if v.Tok == token.IMPORT {
   578  				return true
   579  			}
   580  			var thing string
   581  			switch v.Tok {
   582  			case token.CONST:
   583  				thing = "const"
   584  			case token.TYPE:
   585  				thing = "type"
   586  			case token.VAR:
   587  				thing = "var"
   588  			}
   589  			for _, spec := range v.Specs {
   590  				switch s := spec.(type) {
   591  				case *ast.TypeSpec:
   592  					check(s.Name, thing)
   593  				case *ast.ValueSpec:
   594  					for _, id := range s.Names {
   595  						check(id, thing)
   596  					}
   597  				}
   598  			}
   599  		case *ast.InterfaceType:
   600  			// Do not check interface method names.
   601  			// They are often constrainted by the method names of concrete types.
   602  			for _, x := range v.Methods.List {
   603  				ft, ok := x.Type.(*ast.FuncType)
   604  				if !ok { // might be an embedded interface name
   605  					continue
   606  				}
   607  				checkList(ft.Params, "interface method parameter")
   608  				checkList(ft.Results, "interface method result")
   609  			}
   610  		case *ast.RangeStmt:
   611  			if v.Tok == token.ASSIGN {
   612  				return true
   613  			}
   614  			if id, ok := v.Key.(*ast.Ident); ok {
   615  				check(id, "range var")
   616  			}
   617  			if id, ok := v.Value.(*ast.Ident); ok {
   618  				check(id, "range var")
   619  			}
   620  		case *ast.StructType:
   621  			for _, f := range v.Fields.List {
   622  				for _, id := range f.Names {
   623  					check(id, "struct field")
   624  				}
   625  			}
   626  		}
   627  		return true
   628  	})
   629  }
   630  
   631  // lintName returns a different name if it should be different.
   632  func lintName(name string) (should string) {
   633  	// Fast path for simple cases: "_" and all lowercase.
   634  	if name == "_" {
   635  		return name
   636  	}
   637  	allLower := true
   638  	for _, r := range name {
   639  		if !unicode.IsLower(r) {
   640  			allLower = false
   641  			break
   642  		}
   643  	}
   644  	if allLower {
   645  		return name
   646  	}
   647  
   648  	// Split camelCase at any lower->upper transition, and split on underscores.
   649  	// Check each word for common initialisms.
   650  	runes := []rune(name)
   651  	w, i := 0, 0 // index of start of word, scan
   652  	for i+1 <= len(runes) {
   653  		eow := false // whether we hit the end of a word
   654  		if i+1 == len(runes) {
   655  			eow = true
   656  		} else if runes[i+1] == '_' {
   657  			// underscore; shift the remainder forward over any run of underscores
   658  			eow = true
   659  			n := 1
   660  			for i+n+1 < len(runes) && runes[i+n+1] == '_' {
   661  				n++
   662  			}
   663  
   664  			// Leave at most one underscore if the underscore is between two digits
   665  			if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
   666  				n--
   667  			}
   668  
   669  			copy(runes[i+1:], runes[i+n+1:])
   670  			runes = runes[:len(runes)-n]
   671  		} else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
   672  			// lower->non-lower
   673  			eow = true
   674  		}
   675  		i++
   676  		if !eow {
   677  			continue
   678  		}
   679  
   680  		// [w,i) is a word.
   681  		word := string(runes[w:i])
   682  		if u := strings.ToUpper(word); commonInitialisms[u] {
   683  			// Keep consistent case, which is lowercase only at the start.
   684  			if w == 0 && unicode.IsLower(runes[w]) {
   685  				u = strings.ToLower(u)
   686  			}
   687  			// All the common initialisms are ASCII,
   688  			// so we can replace the bytes exactly.
   689  			copy(runes[w:], []rune(u))
   690  		} else if w > 0 && strings.ToLower(word) == word {
   691  			// already all lowercase, and not the first word, so uppercase the first character.
   692  			runes[w] = unicode.ToUpper(runes[w])
   693  		}
   694  		w = i
   695  	}
   696  	return string(runes)
   697  }
   698  
   699  // commonInitialisms is a set of common initialisms.
   700  // Only add entries that are highly unlikely to be non-initialisms.
   701  // For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
   702  var commonInitialisms = map[string]bool{
   703  	"API":   true,
   704  	"ASCII": true,
   705  	"CPU":   true,
   706  	"CSS":   true,
   707  	"DNS":   true,
   708  	"EOF":   true,
   709  	"GUID":  true,
   710  	"HTML":  true,
   711  	"HTTP":  true,
   712  	"HTTPS": true,
   713  	"ID":    true,
   714  	"IP":    true,
   715  	"JSON":  true,
   716  	"LHS":   true,
   717  	"QPS":   true,
   718  	"RAM":   true,
   719  	"RHS":   true,
   720  	"RPC":   true,
   721  	"SLA":   true,
   722  	"SMTP":  true,
   723  	"SQL":   true,
   724  	"SSH":   true,
   725  	"TCP":   true,
   726  	"TLS":   true,
   727  	"TTL":   true,
   728  	"UDP":   true,
   729  	"UI":    true,
   730  	"UID":   true,
   731  	"UUID":  true,
   732  	"URI":   true,
   733  	"URL":   true,
   734  	"UTF8":  true,
   735  	"VM":    true,
   736  	"XML":   true,
   737  	"XSRF":  true,
   738  	"XSS":   true,
   739  }
   740  
   741  // lintTypeDoc examines the doc comment on a type.
   742  // It complains if they are missing from an exported type,
   743  // or if they are not of the standard form.
   744  func (f *file) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) {
   745  	if !ast.IsExported(t.Name.Name) {
   746  		return
   747  	}
   748  	if doc == nil {
   749  		f.errorf(t, 1, link(docCommentsLink), category("comments"), "exported type %v should have comment or be unexported", t.Name)
   750  		return
   751  	}
   752  
   753  	s := doc.Text()
   754  	articles := [...]string{"A", "An", "The"}
   755  	for _, a := range articles {
   756  		if strings.HasPrefix(s, a+" ") {
   757  			s = s[len(a)+1:]
   758  			break
   759  		}
   760  	}
   761  	if !strings.HasPrefix(s, t.Name.Name+" ") {
   762  		f.errorf(doc, 1, link(docCommentsLink), category("comments"), `comment on exported type %v should be of the form "%v ..." (with optional leading article)`, t.Name, t.Name)
   763  	}
   764  }
   765  
   766  var commonMethods = map[string]bool{
   767  	"Error":     true,
   768  	"Read":      true,
   769  	"ServeHTTP": true,
   770  	"String":    true,
   771  	"Write":     true,
   772  }
   773  
   774  // lintFuncDoc examines doc comments on functions and methods.
   775  // It complains if they are missing, or not of the right form.
   776  // It has specific exclusions for well-known methods (see commonMethods above).
   777  func (f *file) lintFuncDoc(fn *ast.FuncDecl) {
   778  	if !ast.IsExported(fn.Name.Name) {
   779  		// func is unexported
   780  		return
   781  	}
   782  	kind := "function"
   783  	name := fn.Name.Name
   784  	if fn.Recv != nil && len(fn.Recv.List) > 0 {
   785  		// method
   786  		kind = "method"
   787  		recv := receiverType(fn)
   788  		if !ast.IsExported(recv) {
   789  			// receiver is unexported
   790  			return
   791  		}
   792  		if commonMethods[name] {
   793  			return
   794  		}
   795  		switch name {
   796  		case "Len", "Less", "Swap":
   797  			if f.pkg.sortable[recv] {
   798  				return
   799  			}
   800  		}
   801  		name = recv + "." + name
   802  	}
   803  	if fn.Doc == nil {
   804  		f.errorf(fn, 1, link(docCommentsLink), category("comments"), "exported %s %s should have comment or be unexported", kind, name)
   805  		return
   806  	}
   807  	s := fn.Doc.Text()
   808  	prefix := fn.Name.Name + " "
   809  	if !strings.HasPrefix(s, prefix) {
   810  		f.errorf(fn.Doc, 1, link(docCommentsLink), category("comments"), `comment on exported %s %s should be of the form "%s..."`, kind, name, prefix)
   811  	}
   812  }
   813  
   814  // lintValueSpecDoc examines package-global variables and constants.
   815  // It complains if they are not individually declared,
   816  // or if they are not suitably documented in the right form (unless they are in a block that is commented).
   817  func (f *file) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genDeclMissingComments map[*ast.GenDecl]bool) {
   818  	kind := "var"
   819  	if gd.Tok == token.CONST {
   820  		kind = "const"
   821  	}
   822  
   823  	if len(vs.Names) > 1 {
   824  		// Check that none are exported except for the first.
   825  		for _, n := range vs.Names[1:] {
   826  			if ast.IsExported(n.Name) {
   827  				f.errorf(vs, 1, category("comments"), "exported %s %s should have its own declaration", kind, n.Name)
   828  				return
   829  			}
   830  		}
   831  	}
   832  
   833  	// Only one name.
   834  	name := vs.Names[0].Name
   835  	if !ast.IsExported(name) {
   836  		return
   837  	}
   838  
   839  	if vs.Doc == nil && gd.Doc == nil {
   840  		if genDeclMissingComments[gd] {
   841  			return
   842  		}
   843  		block := ""
   844  		if kind == "const" && gd.Lparen.IsValid() {
   845  			block = " (or a comment on this block)"
   846  		}
   847  		f.errorf(vs, 1, link(docCommentsLink), category("comments"), "exported %s %s should have comment%s or be unexported", kind, name, block)
   848  		genDeclMissingComments[gd] = true
   849  		return
   850  	}
   851  	// If this GenDecl has parens and a comment, we don't check its comment form.
   852  	if gd.Lparen.IsValid() && gd.Doc != nil {
   853  		return
   854  	}
   855  	// The relevant text to check will be on either vs.Doc or gd.Doc.
   856  	// Use vs.Doc preferentially.
   857  	doc := vs.Doc
   858  	if doc == nil {
   859  		doc = gd.Doc
   860  	}
   861  	prefix := name + " "
   862  	if !strings.HasPrefix(doc.Text(), prefix) {
   863  		f.errorf(doc, 1, link(docCommentsLink), category("comments"), `comment on exported %s %s should be of the form "%s..."`, kind, name, prefix)
   864  	}
   865  }
   866  
   867  func (f *file) checkStutter(id *ast.Ident, thing string) {
   868  	pkg, name := f.f.Name.Name, id.Name
   869  	if !ast.IsExported(name) {
   870  		// unexported name
   871  		return
   872  	}
   873  	// A name stutters if the package name is a strict prefix
   874  	// and the next character of the name starts a new word.
   875  	if len(name) <= len(pkg) {
   876  		// name is too short to stutter.
   877  		// This permits the name to be the same as the package name.
   878  		return
   879  	}
   880  	if !strings.EqualFold(pkg, name[:len(pkg)]) {
   881  		return
   882  	}
   883  	// We can assume the name is well-formed UTF-8.
   884  	// If the next rune after the package name is uppercase or an underscore
   885  	// the it's starting a new word and thus this name stutters.
   886  	rem := name[len(pkg):]
   887  	if next, _ := utf8.DecodeRuneInString(rem); next == '_' || unicode.IsUpper(next) {
   888  		f.errorf(id, 0.8, link(styleGuideBase+"#package-names"), category("naming"), "%s name will be used as %s.%s by other packages, and that stutters; consider calling this %s", thing, pkg, name, rem)
   889  	}
   890  }
   891  
   892  // zeroLiteral is a set of ast.BasicLit values that are zero values.
   893  // It is not exhaustive.
   894  var zeroLiteral = map[string]bool{
   895  	"false": true, // bool
   896  	// runes
   897  	`'\x00'`: true,
   898  	`'\000'`: true,
   899  	// strings
   900  	`""`: true,
   901  	"``": true,
   902  	// numerics
   903  	"0":   true,
   904  	"0.":  true,
   905  	"0.0": true,
   906  	"0i":  true,
   907  }
   908  
   909  // knownWeakerTypes is a set of types that are commonly used to weaken var declarations.
   910  // A common form of var declarations that legitimately mentions an explicit LHS type
   911  // is where the LHS type is "weaker" than the exact RHS type, where "weaker" means an
   912  // interface compared to a concrete type, or an interface compared to a superset interface.
   913  // A canonical example is `var out io.Writer = os.Stdout`.
   914  // This is only used when type checking fails to determine the exact types.
   915  var knownWeakerTypes = map[string]bool{
   916  	"io.Reader":     true,
   917  	"io.Writer":     true,
   918  	"proto.Message": true,
   919  }
   920  
   921  // lintVarDecls examines variable declarations. It complains about declarations with
   922  // redundant LHS types that can be inferred from the RHS.
   923  func (f *file) lintVarDecls() {
   924  	var lastGen *ast.GenDecl // last GenDecl entered.
   925  
   926  	f.walk(func(node ast.Node) bool {
   927  		switch v := node.(type) {
   928  		case *ast.GenDecl:
   929  			if v.Tok != token.CONST && v.Tok != token.VAR {
   930  				return false
   931  			}
   932  			lastGen = v
   933  			return true
   934  		case *ast.ValueSpec:
   935  			if lastGen.Tok == token.CONST {
   936  				return false
   937  			}
   938  			if len(v.Names) > 1 || v.Type == nil || len(v.Values) == 0 {
   939  				return false
   940  			}
   941  			rhs := v.Values[0]
   942  			// An underscore var appears in a common idiom for compile-time interface satisfaction,
   943  			// as in "var _ Interface = (*Concrete)(nil)".
   944  			if isIdent(v.Names[0], "_") {
   945  				return false
   946  			}
   947  			// If the RHS is a zero value, suggest dropping it.
   948  			zero := false
   949  			if lit, ok := rhs.(*ast.BasicLit); ok {
   950  				zero = zeroLiteral[lit.Value]
   951  			} else if isIdent(rhs, "nil") {
   952  				zero = true
   953  			}
   954  			if zero {
   955  				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])
   956  				return false
   957  			}
   958  			lhsTyp := f.pkg.typeOf(v.Type)
   959  			rhsTyp := f.pkg.typeOf(rhs)
   960  			if lhsTyp != nil && rhsTyp != nil && !types.Identical(lhsTyp, rhsTyp) {
   961  				// Assignment to a different type is not redundant.
   962  				return false
   963  			}
   964  
   965  			// The next three conditions are for suppressing the warning in situations
   966  			// where we were unable to typecheck.
   967  
   968  			// If the LHS type is an interface, don't warn, since it is probably a
   969  			// concrete type on the RHS. Note that our feeble lexical check here
   970  			// will only pick up interface{} and other literal interface types;
   971  			// that covers most of the cases we care to exclude right now.
   972  			if _, ok := v.Type.(*ast.InterfaceType); ok {
   973  				return false
   974  			}
   975  			// If the RHS is an untyped const, only warn if the LHS type is its default type.
   976  			if defType, ok := f.isUntypedConst(rhs); ok && !isIdent(v.Type, defType) {
   977  				return false
   978  			}
   979  			// If the LHS is a known weaker type, and we couldn't type check both sides,
   980  			// don't warn.
   981  			if lhsTyp == nil || rhsTyp == nil {
   982  				if knownWeakerTypes[f.render(v.Type)] {
   983  					return false
   984  				}
   985  			}
   986  
   987  			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])
   988  			return false
   989  		}
   990  		return true
   991  	})
   992  }
   993  
   994  // lintElses examines else blocks. It complains about any else block whose if block ends in a return.
   995  func (f *file) lintElses() {
   996  	// We don't want to flag if { } else if { } else { } constructions.
   997  	// They will appear as an IfStmt whose Else field is also an IfStmt.
   998  	// Record such a node so we ignore it when we visit it.
   999  	ignore := make(map[*ast.IfStmt]bool)
  1000  
  1001  	f.walk(func(node ast.Node) bool {
  1002  		ifStmt, ok := node.(*ast.IfStmt)
  1003  		if !ok || ifStmt.Else == nil {
  1004  			return true
  1005  		}
  1006  		if ignore[ifStmt] {
  1007  			return true
  1008  		}
  1009  		if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok {
  1010  			ignore[elseif] = true
  1011  			return true
  1012  		}
  1013  		if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok {
  1014  			// only care about elses without conditions
  1015  			return true
  1016  		}
  1017  		if len(ifStmt.Body.List) == 0 {
  1018  			return true
  1019  		}
  1020  		shortDecl := false // does the if statement have a ":=" initialization statement?
  1021  		if ifStmt.Init != nil {
  1022  			if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE {
  1023  				shortDecl = true
  1024  			}
  1025  		}
  1026  		lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1]
  1027  		if _, ok := lastStmt.(*ast.ReturnStmt); ok {
  1028  			extra := ""
  1029  			if shortDecl {
  1030  				extra = " (move short variable declaration to its own line if necessary)"
  1031  			}
  1032  			f.errorf(ifStmt.Else, 1, link(styleGuideBase+"#indent-error-flow"), category("indent"), "if block ends with a return statement, so drop this else and outdent its block"+extra)
  1033  		}
  1034  		return true
  1035  	})
  1036  }
  1037  
  1038  // lintRanges examines range clauses. It complains about redundant constructions.
  1039  func (f *file) lintRanges() {
  1040  	f.walk(func(node ast.Node) bool {
  1041  		rs, ok := node.(*ast.RangeStmt)
  1042  		if !ok {
  1043  			return true
  1044  		}
  1045  		if rs.Value == nil {
  1046  			// for x = range m { ... }
  1047  			return true // single var form
  1048  		}
  1049  		if !isIdent(rs.Value, "_") {
  1050  			// for ?, y = range m { ... }
  1051  			return true
  1052  		}
  1053  
  1054  		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)
  1055  
  1056  		newRS := *rs // shallow copy
  1057  		newRS.Value = nil
  1058  		p.ReplacementLine = f.firstLineOf(&newRS, rs)
  1059  
  1060  		return true
  1061  	})
  1062  }
  1063  
  1064  // lintErrorf examines errors.New and testing.Error calls. It complains if its only argument is an fmt.Sprintf invocation.
  1065  func (f *file) lintErrorf() {
  1066  	f.walk(func(node ast.Node) bool {
  1067  		ce, ok := node.(*ast.CallExpr)
  1068  		if !ok || len(ce.Args) != 1 {
  1069  			return true
  1070  		}
  1071  		isErrorsNew := isPkgDot(ce.Fun, "errors", "New")
  1072  		var isTestingError bool
  1073  		se, ok := ce.Fun.(*ast.SelectorExpr)
  1074  		if ok && se.Sel.Name == "Error" {
  1075  			if typ := f.pkg.typeOf(se.X); typ != nil {
  1076  				isTestingError = typ.String() == "*testing.T"
  1077  			}
  1078  		}
  1079  		if !isErrorsNew && !isTestingError {
  1080  			return true
  1081  		}
  1082  		arg := ce.Args[0]
  1083  		ce, ok = arg.(*ast.CallExpr)
  1084  		if !ok || !isPkgDot(ce.Fun, "fmt", "Sprintf") {
  1085  			return true
  1086  		}
  1087  		errorfPrefix := "fmt"
  1088  		if isTestingError {
  1089  			errorfPrefix = f.render(se.X)
  1090  		}
  1091  		p := f.errorf(node, 1, category("errors"), "should replace %s(fmt.Sprintf(...)) with %s.Errorf(...)", f.render(se), errorfPrefix)
  1092  
  1093  		m := f.srcLineWithMatch(ce, `^(.*)`+f.render(se)+`\(fmt\.Sprintf\((.*)\)\)(.*)$`)
  1094  		if m != nil {
  1095  			p.ReplacementLine = m[1] + errorfPrefix + ".Errorf(" + m[2] + ")" + m[3]
  1096  		}
  1097  
  1098  		return true
  1099  	})
  1100  }
  1101  
  1102  // lintErrors examines global error vars. It complains if they aren't named in the standard way.
  1103  func (f *file) lintErrors() {
  1104  	for _, decl := range f.f.Decls {
  1105  		gd, ok := decl.(*ast.GenDecl)
  1106  		if !ok || gd.Tok != token.VAR {
  1107  			continue
  1108  		}
  1109  		for _, spec := range gd.Specs {
  1110  			spec := spec.(*ast.ValueSpec)
  1111  			if len(spec.Names) != 1 || len(spec.Values) != 1 {
  1112  				continue
  1113  			}
  1114  			ce, ok := spec.Values[0].(*ast.CallExpr)
  1115  			if !ok {
  1116  				continue
  1117  			}
  1118  			if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
  1119  				continue
  1120  			}
  1121  
  1122  			id := spec.Names[0]
  1123  			prefix := "err"
  1124  			if id.IsExported() {
  1125  				prefix = "Err"
  1126  			}
  1127  			if !strings.HasPrefix(id.Name, prefix) {
  1128  				f.errorf(id, 0.9, category("naming"), "error var %s should have name of the form %sFoo", id.Name, prefix)
  1129  			}
  1130  		}
  1131  	}
  1132  }
  1133  
  1134  func lintCapAndPunct(s string) (isCap, isPunct bool) {
  1135  	first, firstN := utf8.DecodeRuneInString(s)
  1136  	last, _ := utf8.DecodeLastRuneInString(s)
  1137  	isPunct = last == '.' || last == ':' || last == '!'
  1138  	isCap = unicode.IsUpper(first)
  1139  	if isCap && len(s) > firstN {
  1140  		// Don't flag strings starting with something that looks like an initialism.
  1141  		if second, _ := utf8.DecodeRuneInString(s[firstN:]); unicode.IsUpper(second) {
  1142  			isCap = false
  1143  		}
  1144  	}
  1145  	return
  1146  }
  1147  
  1148  // lintErrorStrings examines error strings. It complains if they are capitalized or end in punctuation.
  1149  func (f *file) lintErrorStrings() {
  1150  	f.walk(func(node ast.Node) bool {
  1151  		ce, ok := node.(*ast.CallExpr)
  1152  		if !ok {
  1153  			return true
  1154  		}
  1155  		if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") {
  1156  			return true
  1157  		}
  1158  		if len(ce.Args) < 1 {
  1159  			return true
  1160  		}
  1161  		str, ok := ce.Args[0].(*ast.BasicLit)
  1162  		if !ok || str.Kind != token.STRING {
  1163  			return true
  1164  		}
  1165  		s, _ := strconv.Unquote(str.Value) // can assume well-formed Go
  1166  		if s == "" {
  1167  			return true
  1168  		}
  1169  		isCap, isPunct := lintCapAndPunct(s)
  1170  		var msg string
  1171  		switch {
  1172  		case isCap && isPunct:
  1173  			msg = "error strings should not be capitalized and should not end with punctuation"
  1174  		case isCap:
  1175  			msg = "error strings should not be capitalized"
  1176  		case isPunct:
  1177  			msg = "error strings should not end with punctuation"
  1178  		default:
  1179  			return true
  1180  		}
  1181  		// People use proper nouns and exported Go identifiers in error strings,
  1182  		// so decrease the confidence of warnings for capitalization.
  1183  		conf := 0.8
  1184  		if isCap {
  1185  			conf = 0.6
  1186  		}
  1187  		f.errorf(str, conf, link(styleGuideBase+"#error-strings"), category("errors"), msg)
  1188  		return true
  1189  	})
  1190  }
  1191  
  1192  var badReceiverNames = map[string]bool{
  1193  	"me":   true,
  1194  	"this": true,
  1195  	"self": true,
  1196  }
  1197  
  1198  // lintReceiverNames examines receiver names. It complains about inconsistent
  1199  // names used for the same type and names such as "this".
  1200  func (f *file) lintReceiverNames() {
  1201  	typeReceiver := map[string]string{}
  1202  	f.walk(func(n ast.Node) bool {
  1203  		fn, ok := n.(*ast.FuncDecl)
  1204  		if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 {
  1205  			return true
  1206  		}
  1207  		names := fn.Recv.List[0].Names
  1208  		if len(names) < 1 {
  1209  			return true
  1210  		}
  1211  		name := names[0].Name
  1212  		const ref = styleGuideBase + "#receiver-names"
  1213  		if name == "_" {
  1214  			f.errorf(n, 1, link(ref), category("naming"), `receiver name should not be an underscore`)
  1215  			return true
  1216  		}
  1217  		if badReceiverNames[name] {
  1218  			f.errorf(n, 1, link(ref), category("naming"), `receiver name should be a reflection of its identity; don't use generic names such as "me", "this", or "self"`)
  1219  			return true
  1220  		}
  1221  		recv := receiverType(fn)
  1222  		if prev, ok := typeReceiver[recv]; ok && prev != name {
  1223  			f.errorf(n, 1, link(ref), category("naming"), "receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv)
  1224  			return true
  1225  		}
  1226  		typeReceiver[recv] = name
  1227  		return true
  1228  	})
  1229  }
  1230  
  1231  // lintIncDec examines statements that increment or decrement a variable.
  1232  // It complains if they don't use x++ or x--.
  1233  func (f *file) lintIncDec() {
  1234  	f.walk(func(n ast.Node) bool {
  1235  		as, ok := n.(*ast.AssignStmt)
  1236  		if !ok {
  1237  			return true
  1238  		}
  1239  		if len(as.Lhs) != 1 {
  1240  			return true
  1241  		}
  1242  		if !isOne(as.Rhs[0]) {
  1243  			return true
  1244  		}
  1245  		var suffix string
  1246  		switch as.Tok {
  1247  		case token.ADD_ASSIGN:
  1248  			suffix = "++"
  1249  		case token.SUB_ASSIGN:
  1250  			suffix = "--"
  1251  		default:
  1252  			return true
  1253  		}
  1254  		f.errorf(as, 0.8, category("unary-op"), "should replace %s with %s%s", f.render(as), f.render(as.Lhs[0]), suffix)
  1255  		return true
  1256  	})
  1257  }
  1258  
  1259  // lintMake examines statements that declare and initialize a variable with make.
  1260  // It complains if they are constructing a zero element slice.
  1261  func (f *file) lintMake() {
  1262  	f.walk(func(n ast.Node) bool {
  1263  		as, ok := n.(*ast.AssignStmt)
  1264  		if !ok {
  1265  			return true
  1266  		}
  1267  		// Only want single var := assignment statements.
  1268  		if len(as.Lhs) != 1 || as.Tok != token.DEFINE {
  1269  			return true
  1270  		}
  1271  		ce, ok := as.Rhs[0].(*ast.CallExpr)
  1272  		if !ok {
  1273  			return true
  1274  		}
  1275  		// Check if ce is make([]T, 0).
  1276  		if !isIdent(ce.Fun, "make") || len(ce.Args) != 2 || !isZero(ce.Args[1]) {
  1277  			return true
  1278  		}
  1279  		at, ok := ce.Args[0].(*ast.ArrayType)
  1280  		if !ok || at.Len != nil {
  1281  			return true
  1282  		}
  1283  		f.errorf(as, 0.8, category("slice"), `can probably use "var %s %s" instead`, f.render(as.Lhs[0]), f.render(at))
  1284  		return true
  1285  	})
  1286  }
  1287  
  1288  // lintErrorReturn examines function declarations that return an error.
  1289  // It complains if the error isn't the last parameter.
  1290  func (f *file) lintErrorReturn() {
  1291  	f.walk(func(n ast.Node) bool {
  1292  		fn, ok := n.(*ast.FuncDecl)
  1293  		if !ok || fn.Type.Results == nil {
  1294  			return true
  1295  		}
  1296  		ret := fn.Type.Results.List
  1297  		if len(ret) <= 1 {
  1298  			return true
  1299  		}
  1300  		// An error return parameter should be the last parameter.
  1301  		// Flag any error parameters found before the last.
  1302  		for _, r := range ret[:len(ret)-1] {
  1303  			if isIdent(r.Type, "error") {
  1304  				f.errorf(fn, 0.9, category("arg-order"), "error should be the last type when returning multiple items")
  1305  				break // only flag one
  1306  			}
  1307  		}
  1308  		return true
  1309  	})
  1310  }
  1311  
  1312  // lintUnexportedReturn examines exported function declarations.
  1313  // It complains if any return an unexported type.
  1314  func (f *file) lintUnexportedReturn() {
  1315  	f.walk(func(n ast.Node) bool {
  1316  		fn, ok := n.(*ast.FuncDecl)
  1317  		if !ok {
  1318  			return true
  1319  		}
  1320  		if fn.Type.Results == nil {
  1321  			return false
  1322  		}
  1323  		if !fn.Name.IsExported() {
  1324  			return false
  1325  		}
  1326  		thing := "func"
  1327  		if fn.Recv != nil && len(fn.Recv.List) > 0 {
  1328  			thing = "method"
  1329  			if !ast.IsExported(receiverType(fn)) {
  1330  				// Don't report exported methods of unexported types,
  1331  				// such as private implementations of sort.Interface.
  1332  				return false
  1333  			}
  1334  		}
  1335  		for _, ret := range fn.Type.Results.List {
  1336  			typ := f.pkg.typeOf(ret.Type)
  1337  			if exportedType(typ) {
  1338  				continue
  1339  			}
  1340  			f.errorf(ret.Type, 0.8, category("unexported-type-in-api"),
  1341  				"exported %s %s returns unexported type %s, which can be annoying to use",
  1342  				thing, fn.Name.Name, typ)
  1343  			break // only flag one
  1344  		}
  1345  		return false
  1346  	})
  1347  }
  1348  
  1349  // exportedType reports whether typ is an exported type.
  1350  // It is imprecise, and will err on the side of returning true,
  1351  // such as for composite types.
  1352  func exportedType(typ types.Type) bool {
  1353  	switch T := typ.(type) {
  1354  	case *types.Named:
  1355  		// Builtin types have no package.
  1356  		return T.Obj().Pkg() == nil || T.Obj().Exported()
  1357  	case *types.Map:
  1358  		return exportedType(T.Key()) && exportedType(T.Elem())
  1359  	case interface {
  1360  		Elem() types.Type
  1361  	}: // array, slice, pointer, chan
  1362  		return exportedType(T.Elem())
  1363  	}
  1364  	// Be conservative about other types, such as struct, interface, etc.
  1365  	return true
  1366  }
  1367  
  1368  // timeSuffixes is a list of name suffixes that imply a time unit.
  1369  // This is not an exhaustive list.
  1370  var timeSuffixes = []string{
  1371  	"Sec", "Secs", "Seconds",
  1372  	"Msec", "Msecs",
  1373  	"Milli", "Millis", "Milliseconds",
  1374  	"Usec", "Usecs", "Microseconds",
  1375  	"MS", "Ms",
  1376  }
  1377  
  1378  func (f *file) lintTimeNames() {
  1379  	f.walk(func(node ast.Node) bool {
  1380  		v, ok := node.(*ast.ValueSpec)
  1381  		if !ok {
  1382  			return true
  1383  		}
  1384  		for _, name := range v.Names {
  1385  			origTyp := f.pkg.typeOf(name)
  1386  			// Look for time.Duration or *time.Duration;
  1387  			// the latter is common when using flag.Duration.
  1388  			typ := origTyp
  1389  			if pt, ok := typ.(*types.Pointer); ok {
  1390  				typ = pt.Elem()
  1391  			}
  1392  			if !f.pkg.isNamedType(typ, "time", "Duration") {
  1393  				continue
  1394  			}
  1395  			suffix := ""
  1396  			for _, suf := range timeSuffixes {
  1397  				if strings.HasSuffix(name.Name, suf) {
  1398  					suffix = suf
  1399  					break
  1400  				}
  1401  			}
  1402  			if suffix == "" {
  1403  				continue
  1404  			}
  1405  			f.errorf(v, 0.9, category("time"), "var %s is of type %v; don't use unit-specific suffix %q", name.Name, origTyp, suffix)
  1406  		}
  1407  		return true
  1408  	})
  1409  }
  1410  
  1411  func receiverType(fn *ast.FuncDecl) string {
  1412  	switch e := fn.Recv.List[0].Type.(type) {
  1413  	case *ast.Ident:
  1414  		return e.Name
  1415  	case *ast.StarExpr:
  1416  		return e.X.(*ast.Ident).Name
  1417  	}
  1418  	panic(fmt.Sprintf("unknown method receiver AST node type %T", fn.Recv.List[0].Type))
  1419  }
  1420  
  1421  func (f *file) walk(fn func(ast.Node) bool) {
  1422  	ast.Walk(walker(fn), f.f)
  1423  }
  1424  
  1425  func (f *file) render(x interface{}) string {
  1426  	var buf bytes.Buffer
  1427  	if err := printer.Fprint(&buf, f.fset, x); err != nil {
  1428  		panic(err)
  1429  	}
  1430  	return buf.String()
  1431  }
  1432  
  1433  func (f *file) debugRender(x interface{}) string {
  1434  	var buf bytes.Buffer
  1435  	if err := ast.Fprint(&buf, f.fset, x, nil); err != nil {
  1436  		panic(err)
  1437  	}
  1438  	return buf.String()
  1439  }
  1440  
  1441  // walker adapts a function to satisfy the ast.Visitor interface.
  1442  // The function return whether the walk should proceed into the node's children.
  1443  type walker func(ast.Node) bool
  1444  
  1445  func (w walker) Visit(node ast.Node) ast.Visitor {
  1446  	if w(node) {
  1447  		return w
  1448  	}
  1449  	return nil
  1450  }
  1451  
  1452  func isIdent(expr ast.Expr, ident string) bool {
  1453  	id, ok := expr.(*ast.Ident)
  1454  	return ok && id.Name == ident
  1455  }
  1456  
  1457  // isBlank returns whether id is the blank identifier "_".
  1458  // If id == nil, the answer is false.
  1459  func isBlank(id *ast.Ident) bool { return id != nil && id.Name == "_" }
  1460  
  1461  func isPkgDot(expr ast.Expr, pkg, name string) bool {
  1462  	sel, ok := expr.(*ast.SelectorExpr)
  1463  	return ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name)
  1464  }
  1465  
  1466  func isZero(expr ast.Expr) bool {
  1467  	lit, ok := expr.(*ast.BasicLit)
  1468  	return ok && lit.Kind == token.INT && lit.Value == "0"
  1469  }
  1470  
  1471  func isOne(expr ast.Expr) bool {
  1472  	lit, ok := expr.(*ast.BasicLit)
  1473  	return ok && lit.Kind == token.INT && lit.Value == "1"
  1474  }
  1475  
  1476  var basicTypeKinds = map[types.BasicKind]string{
  1477  	types.UntypedBool:    "bool",
  1478  	types.UntypedInt:     "int",
  1479  	types.UntypedRune:    "rune",
  1480  	types.UntypedFloat:   "float64",
  1481  	types.UntypedComplex: "complex128",
  1482  	types.UntypedString:  "string",
  1483  }
  1484  
  1485  // isUntypedConst reports whether expr is an untyped constant,
  1486  // and indicates what its default type is.
  1487  // scope may be nil.
  1488  func (f *file) isUntypedConst(expr ast.Expr) (defType string, ok bool) {
  1489  	// Re-evaluate expr outside of its context to see if it's untyped.
  1490  	// (An expr evaluated within, for example, an assignment context will get the type of the LHS.)
  1491  	exprStr := f.render(expr)
  1492  	tv, err := types.Eval(f.fset, f.pkg.typesPkg, expr.Pos(), exprStr)
  1493  	if err != nil {
  1494  		return "", false
  1495  	}
  1496  	if b, ok := tv.Type.(*types.Basic); ok {
  1497  		if dt, ok := basicTypeKinds[b.Kind()]; ok {
  1498  			return dt, true
  1499  		}
  1500  	}
  1501  
  1502  	return "", false
  1503  }
  1504  
  1505  // firstLineOf renders the given node and returns its first line.
  1506  // It will also match the indentation of another node.
  1507  func (f *file) firstLineOf(node, match ast.Node) string {
  1508  	line := f.render(node)
  1509  	if i := strings.Index(line, "\n"); i >= 0 {
  1510  		line = line[:i]
  1511  	}
  1512  	return f.indentOf(match) + line
  1513  }
  1514  
  1515  func (f *file) indentOf(node ast.Node) string {
  1516  	line := srcLine(f.src, f.fset.Position(node.Pos()))
  1517  	for i, r := range line {
  1518  		switch r {
  1519  		case ' ', '\t':
  1520  		default:
  1521  			return line[:i]
  1522  		}
  1523  	}
  1524  	return line // unusual or empty line
  1525  }
  1526  
  1527  func (f *file) srcLineWithMatch(node ast.Node, pattern string) (m []string) {
  1528  	line := srcLine(f.src, f.fset.Position(node.Pos()))
  1529  	line = strings.TrimSuffix(line, "\n")
  1530  	rx := regexp.MustCompile(pattern)
  1531  	return rx.FindStringSubmatch(line)
  1532  }
  1533  
  1534  // srcLine returns the complete line at p, including the terminating newline.
  1535  func srcLine(src []byte, p token.Position) string {
  1536  	// Run to end of line in both directions if not at line start/end.
  1537  	lo, hi := p.Offset, p.Offset+1
  1538  	for lo > 0 && src[lo-1] != '\n' {
  1539  		lo--
  1540  	}
  1541  	for hi < len(src) && src[hi-1] != '\n' {
  1542  		hi++
  1543  	}
  1544  	return string(src[lo:hi])
  1545  }