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