buildssa.go 3.2 KB

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