mirror of
https://github.com/golang/go
synced 2024-11-08 14:56:31 -07:00
7454f53604
This means bringing over the examples flag and sorting doc.go. Subsequent changes will generalize the examples flag to a general test naming flag, but let's start with the original code. No more changes to golang.org/x/tools please. This should not have happened (and letting it happen was partly my fault). Change-Id: Ia879ea1d15d82372df14853f919263125dfb7b96 Reviewed-on: https://go-review.googlesource.com/14821 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/types"
|
|
"strings"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
func init() {
|
|
register("example",
|
|
"check for common mistaken usages of documentation examples",
|
|
checkExample,
|
|
funcDecl)
|
|
}
|
|
|
|
func isExampleSuffix(s string) bool {
|
|
r, size := utf8.DecodeRuneInString(s)
|
|
return size > 0 && unicode.IsLower(r)
|
|
}
|
|
|
|
// checkExample walks the documentation example functions checking for common
|
|
// mistakes of misnamed functions, failure to map functions to existing
|
|
// identifiers, etc.
|
|
func checkExample(f *File, node ast.Node) {
|
|
if !strings.HasSuffix(f.name, "_test.go") {
|
|
return
|
|
}
|
|
var (
|
|
pkg = f.pkg
|
|
pkgName = pkg.typesPkg.Name()
|
|
scopes = []*types.Scope{pkg.typesPkg.Scope()}
|
|
lookup = func(name string) types.Object {
|
|
for _, scope := range scopes {
|
|
if o := scope.Lookup(name); o != nil {
|
|
return o
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
)
|
|
if strings.HasSuffix(pkgName, "_test") {
|
|
// Treat 'package foo_test' as an alias for 'package foo'.
|
|
var (
|
|
basePkg = strings.TrimSuffix(pkgName, "_test")
|
|
pkg = f.pkg
|
|
)
|
|
for _, p := range pkg.typesPkg.Imports() {
|
|
if p.Name() == basePkg {
|
|
scopes = append(scopes, p.Scope())
|
|
break
|
|
}
|
|
}
|
|
}
|
|
fn, ok := node.(*ast.FuncDecl)
|
|
if !ok {
|
|
// Ignore non-functions.
|
|
return
|
|
}
|
|
var (
|
|
fnName = fn.Name.Name
|
|
report = func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
|
|
)
|
|
if fn.Recv != nil || !strings.HasPrefix(fnName, "Example") {
|
|
// Ignore methods and types not named "Example".
|
|
return
|
|
}
|
|
if params := fn.Type.Params; len(params.List) != 0 {
|
|
report("%s should be niladic", fnName)
|
|
}
|
|
if results := fn.Type.Results; results != nil && len(results.List) != 0 {
|
|
report("%s should return nothing", fnName)
|
|
}
|
|
if fnName == "Example" {
|
|
// Nothing more to do.
|
|
return
|
|
}
|
|
if filesRun && !includesNonTest {
|
|
// The coherence checks between a test and the package it tests
|
|
// will report false positives if no non-test files have
|
|
// been provided.
|
|
return
|
|
}
|
|
var (
|
|
exName = strings.TrimPrefix(fnName, "Example")
|
|
elems = strings.SplitN(exName, "_", 3)
|
|
ident = elems[0]
|
|
obj = lookup(ident)
|
|
)
|
|
if ident != "" && obj == nil {
|
|
// Check ExampleFoo and ExampleBadFoo.
|
|
report("%s refers to unknown identifier: %s", fnName, ident)
|
|
// Abort since obj is absent and no subsequent checks can be performed.
|
|
return
|
|
}
|
|
if elemCnt := strings.Count(exName, "_"); elemCnt == 0 {
|
|
// Nothing more to do.
|
|
return
|
|
}
|
|
mmbr := elems[1]
|
|
if ident == "" {
|
|
// Check Example_suffix and Example_BadSuffix.
|
|
if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
|
|
report("%s has malformed example suffix: %s", fnName, residual)
|
|
}
|
|
return
|
|
}
|
|
if !isExampleSuffix(mmbr) {
|
|
// Check ExampleFoo_Method and ExampleFoo_BadMethod.
|
|
if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
|
|
report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
|
|
}
|
|
}
|
|
if len(elems) == 3 && !isExampleSuffix(elems[2]) {
|
|
// Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
|
|
report("%s has malformed example suffix: %s", fnName, elems[2])
|
|
}
|
|
return
|
|
}
|