You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-09 15:42:47 +03:00
Add cross-compilation Makefile targets and tar-based releases.
Revamp the build system to be more inline with other Prometheus exporters. Notably add Darwin and Windows build targets, and add support for releases using tar files.
This commit is contained in:
21
tools/vendor/github.com/alexkohler/nakedret/LICENSE
generated
vendored
Normal file
21
tools/vendor/github.com/alexkohler/nakedret/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Alex Kohler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
103
tools/vendor/github.com/alexkohler/nakedret/README.md
generated
vendored
Normal file
103
tools/vendor/github.com/alexkohler/nakedret/README.md
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
# nakedret
|
||||
|
||||
nakedret is a Go static analysis tool to find naked returns in functions greater than a specified function length.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/alexkohler/nakedret
|
||||
|
||||
## Usage
|
||||
|
||||
Similar to other Go static anaylsis tools (such as golint, go vet) , nakedret can be invoked with one or more filenames, directories, or packages named by its import path. Nakedret also supports the `...` wildcard.
|
||||
|
||||
nakedret [flags] files/directories/packages
|
||||
|
||||
Currently, the only flag supported is -l, which is an optional numeric flag to specify the maximum length a function can be (in terms of line length). If not specified, it defaults to 5.
|
||||
|
||||
## Purpose
|
||||
|
||||
As noted in Go's [Code Review comments](https://github.com/golang/go/wiki/CodeReviewComments#named-result-parameters):
|
||||
|
||||
> Naked returns are okay if the function is a handful of lines. Once it's a medium sized function, be explicit with your return
|
||||
> values. Corollary: it's not worth it to name result parameters just because it enables you to use naked returns. Clarity of docs is always more important than saving a line or two in your function.
|
||||
|
||||
This tool aims to catch naked returns on non-trivial functions.
|
||||
|
||||
## Example
|
||||
|
||||
Let's take the `types` package in the Go source as an example:
|
||||
|
||||
```Bash
|
||||
$ nakedret -l 25 types/
|
||||
types/check.go:245 checkFiles naked returns on 26 line function
|
||||
types/typexpr.go:443 collectParams naked returns on 53 line function
|
||||
types/stmt.go:275 caseTypes naked returns on 27 line function
|
||||
types/lookup.go:275 MissingMethod naked returns on 39 line function
|
||||
```
|
||||
|
||||
Below is one of the not so intuitive uses of naked returns in `types/lookup.go` found by nakedret (nakedret will return the line number of the last naked return in the function):
|
||||
|
||||
|
||||
```Go
|
||||
func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
|
||||
// fast path for common case
|
||||
if T.Empty() {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) Consider using method sets here. Might be more efficient.
|
||||
|
||||
if ityp, _ := V.Underlying().(*Interface); ityp != nil {
|
||||
// TODO(gri) allMethods is sorted - can do this more efficiently
|
||||
for _, m := range T.allMethods {
|
||||
_, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
|
||||
switch {
|
||||
case obj == nil:
|
||||
if static {
|
||||
return m, false
|
||||
}
|
||||
case !Identical(obj.Type(), m.typ):
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A concrete type implements T if it implements all methods of T.
|
||||
for _, m := range T.allMethods {
|
||||
obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
|
||||
|
||||
f, _ := obj.(*Func)
|
||||
if f == nil {
|
||||
return m, false
|
||||
}
|
||||
|
||||
if !Identical(f.typ, m.typ) {
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
- Unit tests (may require some refactoring to do correctly)
|
||||
- supporting toggling of `build.Context.UseAllFiles` may be useful for some.
|
||||
- Configuration on whether or not to run on test files
|
||||
- Vim quickfix format?
|
||||
- Globbing support (e.g. nakedret *.go)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests welcome!
|
||||
|
||||
|
||||
## Other static analysis tools
|
||||
|
||||
If you've enjoyed nakedret, take a look at my other static anaylsis tools!
|
||||
|
||||
- [unimport](https://github.com/alexkohler/unimport) - Finds unnecessary import aliases
|
||||
- [prealloc](https://github.com/alexkohler/prealloc) - Finds slice declarations that could potentially be preallocated.
|
310
tools/vendor/github.com/alexkohler/nakedret/import.go
generated
vendored
Normal file
310
tools/vendor/github.com/alexkohler/nakedret/import.go
generated
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
|
||||
This file holds a direct copy of the import path matching code of
|
||||
https://github.com/golang/go/blob/master/src/cmd/go/main.go. It can be
|
||||
replaced when https://golang.org/issue/8768 is resolved.
|
||||
|
||||
It has been updated to follow upstream changes in a few ways.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var buildContext = build.Default
|
||||
|
||||
var (
|
||||
goroot = filepath.Clean(runtime.GOROOT())
|
||||
gorootSrc = filepath.Join(goroot, "src")
|
||||
)
|
||||
|
||||
// importPathsNoDotExpansion returns the import paths to use for the given
|
||||
// command line, but it does no ... expansion.
|
||||
func importPathsNoDotExpansion(args []string) []string {
|
||||
if len(args) == 0 {
|
||||
return []string{"."}
|
||||
}
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
// Arguments are supposed to be import paths, but
|
||||
// as a courtesy to Windows developers, rewrite \ to /
|
||||
// in command-line arguments. Handles .\... and so on.
|
||||
if filepath.Separator == '\\' {
|
||||
a = strings.Replace(a, `\`, `/`, -1)
|
||||
}
|
||||
|
||||
// Put argument in canonical form, but preserve leading ./.
|
||||
if strings.HasPrefix(a, "./") {
|
||||
a = "./" + path.Clean(a)
|
||||
if a == "./." {
|
||||
a = "."
|
||||
}
|
||||
} else {
|
||||
a = path.Clean(a)
|
||||
}
|
||||
if a == "all" || a == "std" {
|
||||
out = append(out, allPackages(a)...)
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// importPaths returns the import paths to use for the given command line.
|
||||
func importPaths(args []string) []string {
|
||||
args = importPathsNoDotExpansion(args)
|
||||
var out []string
|
||||
for _, a := range args {
|
||||
if strings.Contains(a, "...") {
|
||||
if build.IsLocalImport(a) {
|
||||
out = append(out, allPackagesInFS(a)...)
|
||||
} else {
|
||||
out = append(out, allPackages(a)...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// matchPattern(pattern)(name) reports whether
|
||||
// name matches pattern. Pattern is a limited glob
|
||||
// pattern in which '...' means 'any string' and there
|
||||
// is no other special syntax.
|
||||
func matchPattern(pattern string) func(name string) bool {
|
||||
re := regexp.QuoteMeta(pattern)
|
||||
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
|
||||
// Special case: foo/... matches foo too.
|
||||
if strings.HasSuffix(re, `/.*`) {
|
||||
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
|
||||
}
|
||||
reg := regexp.MustCompile(`^` + re + `$`)
|
||||
return func(name string) bool {
|
||||
return reg.MatchString(name)
|
||||
}
|
||||
}
|
||||
|
||||
// hasPathPrefix reports whether the path s begins with the
|
||||
// elements in prefix.
|
||||
func hasPathPrefix(s, prefix string) bool {
|
||||
switch {
|
||||
default:
|
||||
return false
|
||||
case len(s) == len(prefix):
|
||||
return s == prefix
|
||||
case len(s) > len(prefix):
|
||||
if prefix != "" && prefix[len(prefix)-1] == '/' {
|
||||
return strings.HasPrefix(s, prefix)
|
||||
}
|
||||
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
|
||||
}
|
||||
}
|
||||
|
||||
// treeCanMatchPattern(pattern)(name) reports whether
|
||||
// name or children of name can possibly match pattern.
|
||||
// Pattern is the same limited glob accepted by matchPattern.
|
||||
func treeCanMatchPattern(pattern string) func(name string) bool {
|
||||
wildCard := false
|
||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||
wildCard = true
|
||||
pattern = pattern[:i]
|
||||
}
|
||||
return func(name string) bool {
|
||||
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
|
||||
wildCard && strings.HasPrefix(name, pattern)
|
||||
}
|
||||
}
|
||||
|
||||
// allPackages returns all the packages that can be found
|
||||
// under the $GOPATH directories and $GOROOT matching pattern.
|
||||
// The pattern is either "all" (all packages), "std" (standard packages)
|
||||
// or a path including "...".
|
||||
func allPackages(pattern string) []string {
|
||||
pkgs := matchPackages(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackages(pattern string) []string {
|
||||
match := func(string) bool { return true }
|
||||
treeCanMatch := func(string) bool { return true }
|
||||
if pattern != "all" && pattern != "std" {
|
||||
match = matchPattern(pattern)
|
||||
treeCanMatch = treeCanMatchPattern(pattern)
|
||||
}
|
||||
|
||||
have := map[string]bool{
|
||||
"builtin": true, // ignore pseudo-package that exists only for documentation
|
||||
}
|
||||
if !buildContext.CgoEnabled {
|
||||
have["runtime/cgo"] = true // ignore during walk
|
||||
}
|
||||
var pkgs []string
|
||||
|
||||
// Commands
|
||||
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
|
||||
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == cmd {
|
||||
return nil
|
||||
}
|
||||
name := path[len(cmd):]
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
// Commands are all in cmd/, not in subdirectories.
|
||||
if strings.Contains(name, string(filepath.Separator)) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
|
||||
name = "cmd/" + name
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, src := range buildContext.SrcDirs() {
|
||||
if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
|
||||
continue
|
||||
}
|
||||
src = filepath.Clean(src) + string(filepath.Separator)
|
||||
root := src
|
||||
if pattern == "cmd" {
|
||||
root += "cmd" + string(filepath.Separator)
|
||||
}
|
||||
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() || path == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, testdata and vendor directory trees.
|
||||
_, elem := filepath.Split(path)
|
||||
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" || elem == "vendor" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := filepath.ToSlash(path[len(src):])
|
||||
if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
|
||||
// The name "std" is only the standard library.
|
||||
// If the name is cmd, it's the root of the command tree.
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !treeCanMatch(name) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if have[name] {
|
||||
return nil
|
||||
}
|
||||
have[name] = true
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
_, err = buildContext.ImportDir(path, 0)
|
||||
if err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); noGo {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
// allPackagesInFS is like allPackages but is passed a pattern
|
||||
// beginning ./ or ../, meaning it should scan the tree rooted
|
||||
// at the given directory. There are ... in the pattern too.
|
||||
func allPackagesInFS(pattern string) []string {
|
||||
pkgs := matchPackagesInFS(pattern)
|
||||
if len(pkgs) == 0 {
|
||||
fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
|
||||
}
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func matchPackagesInFS(pattern string) []string {
|
||||
// Find directory to begin the scan.
|
||||
// Could be smarter but this one optimization
|
||||
// is enough for now, since ... is usually at the
|
||||
// end of a path.
|
||||
i := strings.Index(pattern, "...")
|
||||
dir, _ := path.Split(pattern[:i])
|
||||
|
||||
// pattern begins with ./ or ../.
|
||||
// path.Clean will discard the ./ but not the ../.
|
||||
// We need to preserve the ./ for pattern matching
|
||||
// and in the returned import paths.
|
||||
prefix := ""
|
||||
if strings.HasPrefix(pattern, "./") {
|
||||
prefix = "./"
|
||||
}
|
||||
match := matchPattern(pattern)
|
||||
|
||||
var pkgs []string
|
||||
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil || !fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if path == dir {
|
||||
// filepath.Walk starts at dir and recurses. For the recursive case,
|
||||
// the path is the result of filepath.Join, which calls filepath.Clean.
|
||||
// The initial case is not Cleaned, though, so we do this explicitly.
|
||||
//
|
||||
// This converts a path like "./io/" to "io". Without this step, running
|
||||
// "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io
|
||||
// package, because prepending the prefix "./" to the unclean path would
|
||||
// result in "././io", and match("././io") returns false.
|
||||
path = filepath.Clean(path)
|
||||
}
|
||||
|
||||
// Avoid .foo, _foo, testdata and vendor directory trees, but do not avoid "." or "..".
|
||||
_, elem := filepath.Split(path)
|
||||
dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
|
||||
if dot || strings.HasPrefix(elem, "_") || elem == "testdata" || elem == "vendor" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
name := prefix + filepath.ToSlash(path)
|
||||
if !match(name) {
|
||||
return nil
|
||||
}
|
||||
if _, err = build.ImportDir(path, 0); err != nil {
|
||||
if _, noGo := err.(*build.NoGoError); !noGo {
|
||||
log.Print(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pkgs = append(pkgs, name)
|
||||
return nil
|
||||
})
|
||||
return pkgs
|
||||
}
|
213
tools/vendor/github.com/alexkohler/nakedret/nakedret.go
generated
vendored
Normal file
213
tools/vendor/github.com/alexkohler/nakedret/nakedret.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
pwd = "./"
|
||||
)
|
||||
|
||||
func init() {
|
||||
//TODO allow build tags
|
||||
build.Default.UseAllFiles = true
|
||||
}
|
||||
|
||||
func usage() {
|
||||
log.Printf("Usage of %s:\n", os.Args[0])
|
||||
log.Printf("\nnakedret [flags] # runs on package in current directory\n")
|
||||
log.Printf("\nnakedret [flags] [packages]\n")
|
||||
log.Printf("Flags:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
type returnsVisitor struct {
|
||||
f *token.FileSet
|
||||
maxLength uint
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Remove log timestamp
|
||||
log.SetFlags(0)
|
||||
|
||||
maxLength := flag.Uint("l", 5, "maximum number of lines for a naked return function")
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
if err := checkNakedReturns(flag.Args(), maxLength); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func checkNakedReturns(args []string, maxLength *uint) error {
|
||||
|
||||
fset := token.NewFileSet()
|
||||
|
||||
files, err := parseInput(args, fset)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse input %v", err)
|
||||
}
|
||||
|
||||
if maxLength == nil {
|
||||
return errors.New("max length nil")
|
||||
}
|
||||
|
||||
retVis := &returnsVisitor{
|
||||
f: fset,
|
||||
maxLength: *maxLength,
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
ast.Walk(retVis, f)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseInput(args []string, fset *token.FileSet) ([]*ast.File, error) {
|
||||
var directoryList []string
|
||||
var fileMode bool
|
||||
files := make([]*ast.File, 0)
|
||||
|
||||
if len(args) == 0 {
|
||||
directoryList = append(directoryList, pwd)
|
||||
} else {
|
||||
for _, arg := range args {
|
||||
if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) {
|
||||
|
||||
for _, dirname := range allPackagesInFS(arg) {
|
||||
directoryList = append(directoryList, dirname)
|
||||
}
|
||||
|
||||
} else if isDir(arg) {
|
||||
directoryList = append(directoryList, arg)
|
||||
|
||||
} else if exists(arg) {
|
||||
if strings.HasSuffix(arg, ".go") {
|
||||
fileMode = true
|
||||
f, err := parser.ParseFile(fset, arg, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, f)
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid file %v specified", arg)
|
||||
}
|
||||
} else {
|
||||
|
||||
//TODO clean this up a bit
|
||||
imPaths := importPaths([]string{arg})
|
||||
for _, importPath := range imPaths {
|
||||
pkg, err := build.Import(importPath, ".", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var stringFiles []string
|
||||
stringFiles = append(stringFiles, pkg.GoFiles...)
|
||||
// files = append(files, pkg.CgoFiles...)
|
||||
stringFiles = append(stringFiles, pkg.TestGoFiles...)
|
||||
if pkg.Dir != "." {
|
||||
for i, f := range stringFiles {
|
||||
stringFiles[i] = filepath.Join(pkg.Dir, f)
|
||||
}
|
||||
}
|
||||
|
||||
fileMode = true
|
||||
for _, stringFile := range stringFiles {
|
||||
f, err := parser.ParseFile(fset, stringFile, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we're not in file mode, then we need to grab each and every package in each directory
|
||||
// we can to grab all the files
|
||||
if !fileMode {
|
||||
for _, fpath := range directoryList {
|
||||
pkgs, err := parser.ParseDir(fset, fpath, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
for _, f := range pkg.Files {
|
||||
files = append(files, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func isDir(filename string) bool {
|
||||
fi, err := os.Stat(filename)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
func exists(filename string) bool {
|
||||
_, err := os.Stat(filename)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (v *returnsVisitor) Visit(node ast.Node) ast.Visitor {
|
||||
var namedReturns []*ast.Ident
|
||||
|
||||
funcDecl, ok := node.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
return v
|
||||
}
|
||||
var functionLineLength int
|
||||
// We've found a function
|
||||
if funcDecl.Type != nil && funcDecl.Type.Results != nil {
|
||||
for _, field := range funcDecl.Type.Results.List {
|
||||
for _, ident := range field.Names {
|
||||
if ident != nil {
|
||||
namedReturns = append(namedReturns, ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
file := v.f.File(funcDecl.Pos())
|
||||
functionLineLength = file.Position(funcDecl.End()).Line - file.Position(funcDecl.Pos()).Line
|
||||
}
|
||||
|
||||
if len(namedReturns) > 0 && funcDecl.Body != nil {
|
||||
// Scan the body for usage of the named returns
|
||||
for _, stmt := range funcDecl.Body.List {
|
||||
|
||||
switch s := stmt.(type) {
|
||||
case *ast.ReturnStmt:
|
||||
if len(s.Results) == 0 {
|
||||
file := v.f.File(s.Pos())
|
||||
if file != nil && uint(functionLineLength) > v.maxLength {
|
||||
if funcDecl.Name != nil {
|
||||
log.Printf("%v:%v %v naked returns on %v line function \n", file.Name(), file.Position(s.Pos()).Line, funcDecl.Name.Name, functionLineLength)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
Reference in New Issue
Block a user