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