github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/example_test.go (about) 1 // Copyright 2013 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 ssa_test 6 7 import ( 8 "fmt" 9 "go/ast" 10 "go/importer" 11 "go/parser" 12 "go/token" 13 "go/types" 14 "log" 15 "os" 16 17 "github.com/powerman/golang-tools/go/packages" 18 "github.com/powerman/golang-tools/go/ssa" 19 "github.com/powerman/golang-tools/go/ssa/ssautil" 20 ) 21 22 const hello = ` 23 package main 24 25 import "fmt" 26 27 const message = "Hello, World!" 28 29 func main() { 30 fmt.Println(message) 31 } 32 ` 33 34 // This program demonstrates how to run the SSA builder on a single 35 // package of one or more already-parsed files. Its dependencies are 36 // loaded from compiler export data. This is what you'd typically use 37 // for a compiler; it does not depend on github.com/powerman/golang-tools/go/loader. 38 // 39 // It shows the printed representation of packages, functions, and 40 // instructions. Within the function listing, the name of each 41 // BasicBlock such as ".0.entry" is printed left-aligned, followed by 42 // the block's Instructions. 43 // 44 // For each instruction that defines an SSA virtual register 45 // (i.e. implements Value), the type of that value is shown in the 46 // right column. 47 // 48 // Build and run the ssadump.go program if you want a standalone tool 49 // with similar functionality. It is located at 50 // github.com/powerman/golang-tools/cmd/ssadump. 51 // 52 func Example_buildPackage() { 53 // Replace interface{} with any for this test. 54 ssa.SetNormalizeAnyForTesting(true) 55 defer ssa.SetNormalizeAnyForTesting(false) 56 // Parse the source files. 57 fset := token.NewFileSet() 58 f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments) 59 if err != nil { 60 fmt.Print(err) // parse error 61 return 62 } 63 files := []*ast.File{f} 64 65 // Create the type-checker's package. 66 pkg := types.NewPackage("hello", "") 67 68 // Type-check the package, load dependencies. 69 // Create and build the SSA program. 70 hello, _, err := ssautil.BuildPackage( 71 &types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions) 72 if err != nil { 73 fmt.Print(err) // type error in some package 74 return 75 } 76 77 // Print out the package. 78 hello.WriteTo(os.Stdout) 79 80 // Print out the package-level functions. 81 hello.Func("init").WriteTo(os.Stdout) 82 hello.Func("main").WriteTo(os.Stdout) 83 84 // Output: 85 // 86 // package hello: 87 // func init func() 88 // var init$guard bool 89 // func main func() 90 // const message message = "Hello, World!":untyped string 91 // 92 // # Name: hello.init 93 // # Package: hello 94 // # Synthetic: package initializer 95 // func init(): 96 // 0: entry P:0 S:2 97 // t0 = *init$guard bool 98 // if t0 goto 2 else 1 99 // 1: init.start P:1 S:1 100 // *init$guard = true:bool 101 // t1 = fmt.init() () 102 // jump 2 103 // 2: init.done P:2 S:0 104 // return 105 // 106 // # Name: hello.main 107 // # Package: hello 108 // # Location: hello.go:8:6 109 // func main(): 110 // 0: entry P:0 S:0 111 // t0 = new [1]any (varargs) *[1]any 112 // t1 = &t0[0:int] *any 113 // t2 = make any <- string ("Hello, World!":string) any 114 // *t1 = t2 115 // t3 = slice t0[:] []any 116 // t4 = fmt.Println(t3...) (n int, err error) 117 // return 118 } 119 120 // This example builds SSA code for a set of packages using the 121 // x/tools/go/packages API. This is what you would typically use for a 122 // analysis capable of operating on a single package. 123 func Example_loadPackages() { 124 // Load, parse, and type-check the initial packages. 125 cfg := &packages.Config{Mode: packages.LoadSyntax} 126 initial, err := packages.Load(cfg, "fmt", "net/http") 127 if err != nil { 128 log.Fatal(err) 129 } 130 131 // Stop if any package had errors. 132 // This step is optional; without it, the next step 133 // will create SSA for only a subset of packages. 134 if packages.PrintErrors(initial) > 0 { 135 log.Fatalf("packages contain errors") 136 } 137 138 // Create SSA packages for all well-typed packages. 139 prog, pkgs := ssautil.Packages(initial, ssa.PrintPackages) 140 _ = prog 141 142 // Build SSA code for the well-typed initial packages. 143 for _, p := range pkgs { 144 if p != nil { 145 p.Build() 146 } 147 } 148 } 149 150 // This example builds SSA code for a set of packages plus all their dependencies, 151 // using the x/tools/go/packages API. 152 // This is what you'd typically use for a whole-program analysis. 153 func Example_loadWholeProgram() { 154 // Load, parse, and type-check the whole program. 155 cfg := packages.Config{Mode: packages.LoadAllSyntax} 156 initial, err := packages.Load(&cfg, "fmt", "net/http") 157 if err != nil { 158 log.Fatal(err) 159 } 160 161 // Create SSA packages for well-typed packages and their dependencies. 162 prog, pkgs := ssautil.AllPackages(initial, ssa.PrintPackages) 163 _ = pkgs 164 165 // Build SSA code for the whole program. 166 prog.Build() 167 }