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