// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ir_test import ( "fmt" "go/ast" "go/importer" "go/parser" "go/token" "go/types" "log" "os" "golang.org/x/tools/go/packages" "honnef.co/go/tools/ir" "honnef.co/go/tools/ir/irutil" ) const hello = ` package main import "fmt" const message = "Hello, World!" func main() { fmt.Println(message) } ` // This program demonstrates how to run the IR builder on a single // package of one or more already-parsed files. Its dependencies are // loaded from compiler export data. This is what you'd typically use // for a compiler; it does not depend on golang.org/x/tools/go/loader. // // It shows the printed representation of packages, functions, and // instructions. Within the function listing, the name of each // BasicBlock such as ".0.entry" is printed left-aligned, followed by // the block's Instructions. // // For each instruction that defines an IR virtual register // (i.e. implements Value), the type of that value is shown in the // right column. // // Build and run the irdump.go program if you want a standalone tool // with similar functionality. It is located at // honnef.co/go/tools/internal/cmd/irdump. // func Example_buildPackage() { // Parse the source files. fset := token.NewFileSet() f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments) if err != nil { fmt.Print(err) // parse error return } files := []*ast.File{f} // Create the type-checker's package. pkg := types.NewPackage("hello", "") // Type-check the package, load dependencies. // Create and build the IR program. hello, _, err := irutil.BuildPackage( &types.Config{Importer: importer.Default()}, fset, pkg, files, ir.SanityCheckFunctions) if err != nil { fmt.Print(err) // type error in some package return } // Print out the package. hello.WriteTo(os.Stdout) // Print out the package-level functions. hello.Func("init").WriteTo(os.Stdout) hello.Func("main").WriteTo(os.Stdout) // Output: // package hello: // func init func() // var init$guard bool // func main func() // const message message = Const {"Hello, World!"} // // # Name: hello.init // # Package: hello // # Synthetic: package initializer // func init(): // b0: # entry // t1 = Const {true} // t2 = Load init$guard // If t2 → b1 b2 // // b1: ← b0 b2 # exit // Return // // b2: ← b0 # init.start // Store {bool} init$guard t1 // t6 = Call <()> fmt.init // Jump → b1 // // # Name: hello.main // # Package: hello // # Location: hello.go:8:1 // func main(): // b0: # entry // t1 = Const {"Hello, World!"} // t2 = Const {0} // t3 = HeapAlloc <*[1]interface{}> // t4 = IndexAddr <*interface{}> t3 t2 // t5 = MakeInterface t1 // Store {interface{}} t4 t5 // t7 = Slice <[]interface{}> t3 // t8 = Call <(n int, err error)> fmt.Println t7 // Jump → b1 // // b1: ← b0 # exit // Return } // This example builds IR code for a set of packages using the // x/tools/go/packages API. This is what you would typically use for a // analysis capable of operating on a single package. func Example_loadPackages() { // Load, parse, and type-check the initial packages. cfg := &packages.Config{Mode: packages.LoadSyntax} initial, err := packages.Load(cfg, "fmt", "net/http") if err != nil { log.Fatal(err) } // Stop if any package had errors. // This step is optional; without it, the next step // will create IR for only a subset of packages. if packages.PrintErrors(initial) > 0 { log.Fatalf("packages contain errors") } // Create IR packages for all well-typed packages. prog, pkgs := irutil.Packages(initial, ir.PrintPackages, nil) _ = prog // Build IR code for the well-typed initial packages. for _, p := range pkgs { if p != nil { p.Build() } } } // This example builds IR code for a set of packages plus all their dependencies, // using the x/tools/go/packages API. // This is what you'd typically use for a whole-program analysis. func Example_loadWholeProgram() { // Load, parse, and type-check the whole program. cfg := packages.Config{Mode: packages.LoadAllSyntax} initial, err := packages.Load(&cfg, "fmt", "net/http") if err != nil { log.Fatal(err) } // Create IR packages for well-typed packages and their dependencies. prog, pkgs := irutil.AllPackages(initial, ir.PrintPackages, nil) _ = pkgs // Build IR code for the whole program. prog.Build() }