golang.org/x/tools@v0.21.0/go/analysis/passes/buildssa/buildssa.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package buildssa defines an Analyzer that constructs the SSA 6 // representation of an error-free package and returns the set of all 7 // functions within it. It does not report any diagnostics itself but 8 // may be used as an input to other analyzers. 9 package buildssa 10 11 import ( 12 "go/ast" 13 "go/types" 14 "reflect" 15 16 "golang.org/x/tools/go/analysis" 17 "golang.org/x/tools/go/ssa" 18 ) 19 20 var Analyzer = &analysis.Analyzer{ 21 Name: "buildssa", 22 Doc: "build SSA-form IR for later passes", 23 URL: "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/buildssa", 24 Run: run, 25 ResultType: reflect.TypeOf(new(SSA)), 26 } 27 28 // SSA provides SSA-form intermediate representation for all the 29 // source functions in the current package. 30 type SSA struct { 31 Pkg *ssa.Package 32 SrcFuncs []*ssa.Function 33 } 34 35 func run(pass *analysis.Pass) (interface{}, error) { 36 // We must create a new Program for each Package because the 37 // analysis API provides no place to hang a Program shared by 38 // all Packages. Consequently, SSA Packages and Functions do not 39 // have a canonical representation across an analysis session of 40 // multiple packages. This is unlikely to be a problem in 41 // practice because the analysis API essentially forces all 42 // packages to be analysed independently, so any given call to 43 // Analysis.Run on a package will see only SSA objects belonging 44 // to a single Program. 45 46 // Some Analyzers may need GlobalDebug, in which case we'll have 47 // to set it globally, but let's wait till we need it. 48 mode := ssa.BuilderMode(0) 49 50 prog := ssa.NewProgram(pass.Fset, mode) 51 52 // Create SSA packages for direct imports. 53 for _, p := range pass.Pkg.Imports() { 54 prog.CreatePackage(p, nil, nil, true) 55 } 56 57 // Create and build the primary package. 58 ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) 59 ssapkg.Build() 60 61 // Compute list of source functions, including literals, 62 // in source order. 63 var funcs []*ssa.Function 64 for _, f := range pass.Files { 65 for _, decl := range f.Decls { 66 if fdecl, ok := decl.(*ast.FuncDecl); ok { 67 // (init functions have distinct Func 68 // objects named "init" and distinct 69 // ssa.Functions named "init#1", ...) 70 71 fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func) 72 if fn == nil { 73 panic(fn) 74 } 75 76 f := ssapkg.Prog.FuncValue(fn) 77 if f == nil { 78 panic(fn) 79 } 80 81 var addAnons func(f *ssa.Function) 82 addAnons = func(f *ssa.Function) { 83 funcs = append(funcs, f) 84 for _, anon := range f.AnonFuncs { 85 addAnons(anon) 86 } 87 } 88 addAnons(f) 89 } 90 } 91 } 92 93 return &SSA{Pkg: ssapkg, SrcFuncs: funcs}, nil 94 }