buildir.go (2566B)
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 buildir defines an Analyzer that constructs the IR 6 // 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 buildir 12 13 import ( 14 "reflect" 15 16 "honnef.co/go/tools/go/ir" 17 18 "golang.org/x/tools/go/analysis" 19 "golang.org/x/tools/go/analysis/passes/ctrlflow" 20 ) 21 22 var Debug = struct { 23 Mode ir.BuilderMode 24 }{} 25 26 var Analyzer = &analysis.Analyzer{ 27 Name: "buildir", 28 Doc: "build IR for later passes", 29 Run: run, 30 ResultType: reflect.TypeFor[*IR](), 31 Requires: []*analysis.Analyzer{ctrlflow.Analyzer}, 32 } 33 34 // IR provides intermediate representation for all the 35 // source functions in the current package. 36 type IR struct { 37 Pkg *ir.Package 38 SrcFuncs []*ir.Function 39 } 40 41 func run(pass *analysis.Pass) (any, error) { 42 cfgs := pass.ResultOf[ctrlflow.Analyzer].(*ctrlflow.CFGs) 43 44 // Plundered from ssautil.BuildPackage. 45 46 // We must create a new Program for each Package because the 47 // analysis API provides no place to hang a Program shared by 48 // all Packages. Consequently, IR Packages and Functions do not 49 // have a canonical representation across an analysis session of 50 // multiple packages. This is unlikely to be a problem in 51 // practice because the analysis API essentially forces all 52 // packages to be analysed independently, so any given call to 53 // Analysis.Run on a package will see only IR objects belonging 54 // to a single Program. 55 56 mode := ir.GlobalDebug 57 if Debug.Mode != 0 { 58 mode = Debug.Mode 59 } 60 61 prog := ir.NewProgram(pass.Fset, mode) 62 63 prog.SetNoReturn(cfgs.NoReturn) 64 65 // Create IR packages for direct imports. 66 for _, p := range pass.Pkg.Imports() { 67 prog.CreatePackage(p, nil, nil, true) 68 } 69 70 // Create and build the primary package. 71 irpkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false) 72 irpkg.Build() 73 74 // Compute list of source functions, including literals, 75 // in source order. 76 var addAnons func(f *ir.Function) 77 funcs := make([]*ir.Function, len(irpkg.Functions)) 78 copy(funcs, irpkg.Functions) 79 addAnons = func(f *ir.Function) { 80 for _, anon := range f.AnonFuncs { 81 funcs = append(funcs, anon) 82 addAnons(anon) 83 } 84 } 85 for _, fn := range irpkg.Functions { 86 addAnons(fn) 87 } 88 89 return &IR{Pkg: irpkg, SrcFuncs: funcs}, nil 90 }