github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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 // 10 // THIS INTERFACE IS EXPERIMENTAL AND MAY BE SUBJECT TO INCOMPATIBLE CHANGE. 11 package buildssa 12 13 import ( 14 "go/ast" 15 "go/types" 16 "reflect" 17 18 "github.com/powerman/golang-tools/go/analysis" 19 "github.com/powerman/golang-tools/go/ssa" 20 ) 21 22 var Analyzer = &analysis.Analyzer{ 23 Name: "buildssa", 24 Doc: "build SSA-form IR for later passes", 25 Run: run, 26 ResultType: reflect.TypeOf(new(SSA)), 27 } 28 29 // SSA provides SSA-form intermediate representation for all the 30 // non-blank source functions in the current package. 31 type SSA struct { 32 Pkg *ssa.Package 33 SrcFuncs []*ssa.Function 34 } 35 36 func run(pass *analysis.Pass) (interface{}, error) { 37 // Plundered from ssautil.BuildPackage. 38 39 // We must create a new Program for each Package because the 40 // analysis API provides no place to hang a Program shared by 41 // all Packages. Consequently, SSA Packages and Functions do not 42 // have a canonical representation across an analysis session of 43 // multiple packages. This is unlikely to be a problem in 44 // practice because the analysis API essentially forces all 45 // packages to be analysed independently, so any given call to 46 // Analysis.Run on a package will see only SSA objects belonging 47 // to a single Program. 48 49 // Some Analyzers may need GlobalDebug, in which case we'll have 50 // to set it globally, but let's wait till we need it. 51 mode := ssa.BuilderMode(0) 52 53 prog := ssa.NewProgram(pass.Fset, mode) 54 55 // Create SSA packages for all imports. 56 // Order is not significant. 57 created := make(map[*types.Package]bool) 58 var createAll func(pkgs []*types.Package) 59 createAll = func(pkgs []*types.Package) { 60 for _, p := range pkgs { 61 if !created[p] { 62 created[p] = true 63 prog.CreatePackage(p, nil, nil, true) 64 createAll(p.Imports()) 65 } 66 } 67 } 68 createAll(pass.Pkg.Imports()) 69 70 // Create and build the primary package. 71 ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) 72 ssapkg.Build() 73 74 // Compute list of source functions, including literals, 75 // in source order. 76 var funcs []*ssa.Function 77 for _, f := range pass.Files { 78 for _, decl := range f.Decls { 79 if fdecl, ok := decl.(*ast.FuncDecl); ok { 80 81 // SSA will not build a Function 82 // for a FuncDecl named blank. 83 // That's arguably too strict but 84 // relaxing it would break uniqueness of 85 // names of package members. 86 if fdecl.Name.Name == "_" { 87 continue 88 } 89 90 // (init functions have distinct Func 91 // objects named "init" and distinct 92 // ssa.Functions named "init#1", ...) 93 94 fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func) 95 if fn == nil { 96 panic(fn) 97 } 98 99 f := ssapkg.Prog.FuncValue(fn) 100 if f == nil { 101 panic(fn) 102 } 103 104 var addAnons func(f *ssa.Function) 105 addAnons = func(f *ssa.Function) { 106 funcs = append(funcs, f) 107 for _, anon := range f.AnonFuncs { 108 addAnons(anon) 109 } 110 } 111 addAnons(f) 112 } 113 } 114 } 115 116 return &SSA{Pkg: ssapkg, SrcFuncs: funcs}, nil 117 }