mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Add gitea-vet (#10948)
* Add copyright Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add gitea-vet and fix non-compliance Signed-off-by: jolheiser <john.olheiser@gmail.com> * Combine tools.go into build.go and clean up Signed-off-by: jolheiser <john.olheiser@gmail.com> * Remove extra GO111MODULE=on Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
396
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
Normal file
396
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// The unitchecker package defines the main function for an analysis
|
||||
// driver that analyzes a single compilation unit during a build.
|
||||
// It is invoked by a build system such as "go vet":
|
||||
//
|
||||
// $ go vet -vettool=$(which vet)
|
||||
//
|
||||
// It supports the following command-line protocol:
|
||||
//
|
||||
// -V=full describe executable (to the build tool)
|
||||
// -flags describe flags (to the build tool)
|
||||
// foo.cfg description of compilation unit (from the build tool)
|
||||
//
|
||||
// This package does not depend on go/packages.
|
||||
// If you need a standalone tool, use multichecker,
|
||||
// which supports this mode but can also load packages
|
||||
// from source using go/packages.
|
||||
package unitchecker
|
||||
|
||||
// TODO(adonovan):
|
||||
// - with gccgo, go build does not build standard library,
|
||||
// so we will not get to analyze it. Yet we must in order
|
||||
// to create base facts for, say, the fmt package for the
|
||||
// printf checker.
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/internal/analysisflags"
|
||||
"golang.org/x/tools/go/analysis/internal/facts"
|
||||
)
|
||||
|
||||
// A Config describes a compilation unit to be analyzed.
|
||||
// It is provided to the tool in a JSON-encoded file
|
||||
// whose name ends with ".cfg".
|
||||
type Config struct {
|
||||
ID string // e.g. "fmt [fmt.test]"
|
||||
Compiler string
|
||||
Dir string
|
||||
ImportPath string
|
||||
GoFiles []string
|
||||
NonGoFiles []string
|
||||
ImportMap map[string]string
|
||||
PackageFile map[string]string
|
||||
Standard map[string]bool
|
||||
PackageVetx map[string]string
|
||||
VetxOnly bool
|
||||
VetxOutput string
|
||||
SucceedOnTypecheckFailure bool
|
||||
}
|
||||
|
||||
// Main is the main function of a vet-like analysis tool that must be
|
||||
// invoked by a build system to analyze a single package.
|
||||
//
|
||||
// The protocol required by 'go vet -vettool=...' is that the tool must support:
|
||||
//
|
||||
// -flags describe flags in JSON
|
||||
// -V=full describe executable for build caching
|
||||
// foo.cfg perform separate modular analyze on the single
|
||||
// unit described by a JSON config file foo.cfg.
|
||||
//
|
||||
func Main(analyzers ...*analysis.Analyzer) {
|
||||
progname := filepath.Base(os.Args[0])
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix(progname + ": ")
|
||||
|
||||
if err := analysis.Validate(analyzers); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, `%[1]s is a tool for static analysis of Go programs.
|
||||
|
||||
Usage of %[1]s:
|
||||
%.16[1]s unit.cfg # execute analysis specified by config file
|
||||
%.16[1]s help # general help
|
||||
%.16[1]s help name # help on specific analyzer and its flags
|
||||
`, progname)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
analyzers = analysisflags.Parse(analyzers, true)
|
||||
|
||||
args := flag.Args()
|
||||
if len(args) == 0 {
|
||||
flag.Usage()
|
||||
}
|
||||
if args[0] == "help" {
|
||||
analysisflags.Help(progname, analyzers, args[1:])
|
||||
os.Exit(0)
|
||||
}
|
||||
if len(args) != 1 || !strings.HasSuffix(args[0], ".cfg") {
|
||||
log.Fatalf(`invoking "go tool vet" directly is unsupported; use "go vet"`)
|
||||
}
|
||||
Run(args[0], analyzers)
|
||||
}
|
||||
|
||||
// Run reads the *.cfg file, runs the analysis,
|
||||
// and calls os.Exit with an appropriate error code.
|
||||
// It assumes flags have already been set.
|
||||
func Run(configFile string, analyzers []*analysis.Analyzer) {
|
||||
cfg, err := readConfig(configFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fset := token.NewFileSet()
|
||||
results, err := run(fset, cfg, analyzers)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// In VetxOnly mode, the analysis is run only for facts.
|
||||
if !cfg.VetxOnly {
|
||||
if analysisflags.JSON {
|
||||
// JSON output
|
||||
tree := make(analysisflags.JSONTree)
|
||||
for _, res := range results {
|
||||
tree.Add(fset, cfg.ID, res.a.Name, res.diagnostics, res.err)
|
||||
}
|
||||
tree.Print()
|
||||
} else {
|
||||
// plain text
|
||||
exit := 0
|
||||
for _, res := range results {
|
||||
if res.err != nil {
|
||||
log.Println(res.err)
|
||||
exit = 1
|
||||
}
|
||||
}
|
||||
for _, res := range results {
|
||||
for _, diag := range res.diagnostics {
|
||||
analysisflags.PrintPlain(fset, diag)
|
||||
exit = 1
|
||||
}
|
||||
}
|
||||
os.Exit(exit)
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func readConfig(filename string) (*Config, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := new(Config)
|
||||
if err := json.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("cannot decode JSON config file %s: %v", filename, err)
|
||||
}
|
||||
if len(cfg.GoFiles) == 0 {
|
||||
// The go command disallows packages with no files.
|
||||
// The only exception is unsafe, but the go command
|
||||
// doesn't call vet on it.
|
||||
return nil, fmt.Errorf("package has no files: %s", cfg.ImportPath)
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
var importerForCompiler = func(_ *token.FileSet, compiler string, lookup importer.Lookup) types.Importer {
|
||||
// broken legacy implementation (https://golang.org/issue/28995)
|
||||
return importer.For(compiler, lookup)
|
||||
}
|
||||
|
||||
func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]result, error) {
|
||||
// Load, parse, typecheck.
|
||||
var files []*ast.File
|
||||
for _, name := range cfg.GoFiles {
|
||||
f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
if cfg.SucceedOnTypecheckFailure {
|
||||
// Silently succeed; let the compiler
|
||||
// report parse errors.
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
compilerImporter := importerForCompiler(fset, cfg.Compiler, func(path string) (io.ReadCloser, error) {
|
||||
// path is a resolved package path, not an import path.
|
||||
file, ok := cfg.PackageFile[path]
|
||||
if !ok {
|
||||
if cfg.Compiler == "gccgo" && cfg.Standard[path] {
|
||||
return nil, nil // fall back to default gccgo lookup
|
||||
}
|
||||
return nil, fmt.Errorf("no package file for %q", path)
|
||||
}
|
||||
return os.Open(file)
|
||||
})
|
||||
importer := importerFunc(func(importPath string) (*types.Package, error) {
|
||||
path, ok := cfg.ImportMap[importPath] // resolve vendoring, etc
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can't resolve import %q", path)
|
||||
}
|
||||
return compilerImporter.Import(path)
|
||||
})
|
||||
tc := &types.Config{
|
||||
Importer: importer,
|
||||
Sizes: types.SizesFor("gc", build.Default.GOARCH), // assume gccgo ≡ gc?
|
||||
}
|
||||
info := &types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
Defs: make(map[*ast.Ident]types.Object),
|
||||
Uses: make(map[*ast.Ident]types.Object),
|
||||
Implicits: make(map[ast.Node]types.Object),
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
}
|
||||
pkg, err := tc.Check(cfg.ImportPath, fset, files, info)
|
||||
if err != nil {
|
||||
if cfg.SucceedOnTypecheckFailure {
|
||||
// Silently succeed; let the compiler
|
||||
// report type errors.
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Register fact types with gob.
|
||||
// In VetxOnly mode, analyzers are only for their facts,
|
||||
// so we can skip any analysis that neither produces facts
|
||||
// nor depends on any analysis that produces facts.
|
||||
// Also build a map to hold working state and result.
|
||||
type action struct {
|
||||
once sync.Once
|
||||
result interface{}
|
||||
err error
|
||||
usesFacts bool // (transitively uses)
|
||||
diagnostics []analysis.Diagnostic
|
||||
}
|
||||
actions := make(map[*analysis.Analyzer]*action)
|
||||
var registerFacts func(a *analysis.Analyzer) bool
|
||||
registerFacts = func(a *analysis.Analyzer) bool {
|
||||
act, ok := actions[a]
|
||||
if !ok {
|
||||
act = new(action)
|
||||
var usesFacts bool
|
||||
for _, f := range a.FactTypes {
|
||||
usesFacts = true
|
||||
gob.Register(f)
|
||||
}
|
||||
for _, req := range a.Requires {
|
||||
if registerFacts(req) {
|
||||
usesFacts = true
|
||||
}
|
||||
}
|
||||
act.usesFacts = usesFacts
|
||||
actions[a] = act
|
||||
}
|
||||
return act.usesFacts
|
||||
}
|
||||
var filtered []*analysis.Analyzer
|
||||
for _, a := range analyzers {
|
||||
if registerFacts(a) || !cfg.VetxOnly {
|
||||
filtered = append(filtered, a)
|
||||
}
|
||||
}
|
||||
analyzers = filtered
|
||||
|
||||
// Read facts from imported packages.
|
||||
read := func(path string) ([]byte, error) {
|
||||
if vetx, ok := cfg.PackageVetx[path]; ok {
|
||||
return ioutil.ReadFile(vetx)
|
||||
}
|
||||
return nil, nil // no .vetx file, no facts
|
||||
}
|
||||
facts, err := facts.Decode(pkg, read)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// In parallel, execute the DAG of analyzers.
|
||||
var exec func(a *analysis.Analyzer) *action
|
||||
var execAll func(analyzers []*analysis.Analyzer)
|
||||
exec = func(a *analysis.Analyzer) *action {
|
||||
act := actions[a]
|
||||
act.once.Do(func() {
|
||||
execAll(a.Requires) // prefetch dependencies in parallel
|
||||
|
||||
// The inputs to this analysis are the
|
||||
// results of its prerequisites.
|
||||
inputs := make(map[*analysis.Analyzer]interface{})
|
||||
var failed []string
|
||||
for _, req := range a.Requires {
|
||||
reqact := exec(req)
|
||||
if reqact.err != nil {
|
||||
failed = append(failed, req.String())
|
||||
continue
|
||||
}
|
||||
inputs[req] = reqact.result
|
||||
}
|
||||
|
||||
// Report an error if any dependency failed.
|
||||
if failed != nil {
|
||||
sort.Strings(failed)
|
||||
act.err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", "))
|
||||
return
|
||||
}
|
||||
|
||||
factFilter := make(map[reflect.Type]bool)
|
||||
for _, f := range a.FactTypes {
|
||||
factFilter[reflect.TypeOf(f)] = true
|
||||
}
|
||||
|
||||
pass := &analysis.Pass{
|
||||
Analyzer: a,
|
||||
Fset: fset,
|
||||
Files: files,
|
||||
OtherFiles: cfg.NonGoFiles,
|
||||
Pkg: pkg,
|
||||
TypesInfo: info,
|
||||
TypesSizes: tc.Sizes,
|
||||
ResultOf: inputs,
|
||||
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
|
||||
ImportObjectFact: facts.ImportObjectFact,
|
||||
ExportObjectFact: facts.ExportObjectFact,
|
||||
AllObjectFacts: func() []analysis.ObjectFact { return facts.AllObjectFacts(factFilter) },
|
||||
ImportPackageFact: facts.ImportPackageFact,
|
||||
ExportPackageFact: facts.ExportPackageFact,
|
||||
AllPackageFacts: func() []analysis.PackageFact { return facts.AllPackageFacts(factFilter) },
|
||||
}
|
||||
|
||||
t0 := time.Now()
|
||||
act.result, act.err = a.Run(pass)
|
||||
if false {
|
||||
log.Printf("analysis %s = %s", pass, time.Since(t0))
|
||||
}
|
||||
})
|
||||
return act
|
||||
}
|
||||
execAll = func(analyzers []*analysis.Analyzer) {
|
||||
var wg sync.WaitGroup
|
||||
for _, a := range analyzers {
|
||||
wg.Add(1)
|
||||
go func(a *analysis.Analyzer) {
|
||||
_ = exec(a)
|
||||
wg.Done()
|
||||
}(a)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
execAll(analyzers)
|
||||
|
||||
// Return diagnostics and errors from root analyzers.
|
||||
results := make([]result, len(analyzers))
|
||||
for i, a := range analyzers {
|
||||
act := actions[a]
|
||||
results[i].a = a
|
||||
results[i].err = act.err
|
||||
results[i].diagnostics = act.diagnostics
|
||||
}
|
||||
|
||||
data := facts.Encode()
|
||||
if err := ioutil.WriteFile(cfg.VetxOutput, data, 0666); err != nil {
|
||||
return nil, fmt.Errorf("failed to write analysis facts: %v", err)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
type result struct {
|
||||
a *analysis.Analyzer
|
||||
diagnostics []analysis.Diagnostic
|
||||
err error
|
||||
}
|
||||
|
||||
type importerFunc func(path string) (*types.Package, error)
|
||||
|
||||
func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
|
9
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go
generated
vendored
Normal file
9
vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker112.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// +build go1.12
|
||||
|
||||
package unitchecker
|
||||
|
||||
import "go/importer"
|
||||
|
||||
func init() {
|
||||
importerForCompiler = importer.ForCompiler
|
||||
}
|
Reference in New Issue
Block a user