 6a979fb40d
			
		
	
	
		6a979fb40d
		
			
		
	
	
	
	
		
			
			* update staticcheck Don't fork staticcheck: use the upstream version. Remove unneeded SSA loading. * Cache go/analysis facts Don't load unneeded packages for go/analysis. Repeated run of go/analysis linters now 10x faster (2s vs 20s on this repo) than before.
		
			
				
	
	
		
			117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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.
 | |
| 
 | |
| // Package buildssa defines an Analyzer that constructs the SSA
 | |
| // representation of an error-free package and returns the set of all
 | |
| // functions within it. It does not report any diagnostics itself but
 | |
| // may be used as an input to other analyzers.
 | |
| //
 | |
| // THIS INTERFACE IS EXPERIMENTAL AND MAY BE SUBJECT TO INCOMPATIBLE CHANGE.
 | |
| package buildssa
 | |
| 
 | |
| import (
 | |
| 	"go/ast"
 | |
| 	"go/types"
 | |
| 	"reflect"
 | |
| 
 | |
| 	"golang.org/x/tools/go/analysis"
 | |
| 	"honnef.co/go/tools/ssa"
 | |
| )
 | |
| 
 | |
| var Analyzer = &analysis.Analyzer{
 | |
| 	Name:       "buildssa",
 | |
| 	Doc:        "build SSA-form IR for later passes",
 | |
| 	Run:        run,
 | |
| 	ResultType: reflect.TypeOf(new(SSA)),
 | |
| }
 | |
| 
 | |
| // SSA provides SSA-form intermediate representation for all the
 | |
| // non-blank source functions in the current package.
 | |
| type SSA struct {
 | |
| 	Pkg      *ssa.Package
 | |
| 	SrcFuncs []*ssa.Function
 | |
| }
 | |
| 
 | |
| func run(pass *analysis.Pass) (interface{}, error) {
 | |
| 	// Plundered from ssautil.BuildPackage.
 | |
| 
 | |
| 	// We must create a new Program for each Package because the
 | |
| 	// analysis API provides no place to hang a Program shared by
 | |
| 	// all Packages. Consequently, SSA Packages and Functions do not
 | |
| 	// have a canonical representation across an analysis session of
 | |
| 	// multiple packages. This is unlikely to be a problem in
 | |
| 	// practice because the analysis API essentially forces all
 | |
| 	// packages to be analysed independently, so any given call to
 | |
| 	// Analysis.Run on a package will see only SSA objects belonging
 | |
| 	// to a single Program.
 | |
| 
 | |
| 	mode := ssa.GlobalDebug
 | |
| 
 | |
| 	prog := ssa.NewProgram(pass.Fset, mode)
 | |
| 
 | |
| 	// Create SSA packages for all imports.
 | |
| 	// Order is not significant.
 | |
| 	created := make(map[*types.Package]bool)
 | |
| 	var createAll func(pkgs []*types.Package)
 | |
| 	createAll = func(pkgs []*types.Package) {
 | |
| 		for _, p := range pkgs {
 | |
| 			if !created[p] {
 | |
| 				created[p] = true
 | |
| 				prog.CreatePackage(p, nil, nil, true)
 | |
| 				createAll(p.Imports())
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	createAll(pass.Pkg.Imports())
 | |
| 
 | |
| 	// Create and build the primary package.
 | |
| 	ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false)
 | |
| 	ssapkg.Build()
 | |
| 
 | |
| 	// Compute list of source functions, including literals,
 | |
| 	// in source order.
 | |
| 	var funcs []*ssa.Function
 | |
| 	var addAnons func(f *ssa.Function)
 | |
| 	addAnons = func(f *ssa.Function) {
 | |
| 		funcs = append(funcs, f)
 | |
| 		for _, anon := range f.AnonFuncs {
 | |
| 			addAnons(anon)
 | |
| 		}
 | |
| 	}
 | |
| 	addAnons(ssapkg.Members["init"].(*ssa.Function))
 | |
| 	for _, f := range pass.Files {
 | |
| 		for _, decl := range f.Decls {
 | |
| 			if fdecl, ok := decl.(*ast.FuncDecl); ok {
 | |
| 
 | |
| 				// SSA will not build a Function
 | |
| 				// for a FuncDecl named blank.
 | |
| 				// That's arguably too strict but
 | |
| 				// relaxing it would break uniqueness of
 | |
| 				// names of package members.
 | |
| 				if fdecl.Name.Name == "_" {
 | |
| 					continue
 | |
| 				}
 | |
| 
 | |
| 				// (init functions have distinct Func
 | |
| 				// objects named "init" and distinct
 | |
| 				// ssa.Functions named "init#1", ...)
 | |
| 
 | |
| 				fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func)
 | |
| 				if fn == nil {
 | |
| 					panic(fn)
 | |
| 				}
 | |
| 
 | |
| 				f := ssapkg.Prog.FuncValue(fn)
 | |
| 				if f == nil {
 | |
| 					panic(fn)
 | |
| 				}
 | |
| 
 | |
| 				addAnons(f)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &SSA{Pkg: ssapkg, SrcFuncs: funcs}, nil
 | |
| }
 |