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