github.com/jd-ly/tools@v0.5.7/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  package ssa_test
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/importer"
    11  	"go/parser"
    12  	"go/token"
    13  	"go/types"
    14  	"log"
    15  	"os"
    16  
    17  	"github.com/jd-ly/tools/go/packages"
    18  	"github.com/jd-ly/tools/go/ssa"
    19  	"github.com/jd-ly/tools/go/ssa/ssautil"
    20  )
    21  
    22  const hello = `
    23  package main
    24  
    25  import "fmt"
    26  
    27  const message = "Hello, World!"
    28  
    29  func main() {
    30  	fmt.Println(message)
    31  }
    32  `
    33  
    34  // This program demonstrates how to run the SSA 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 github.com/jd-ly/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 SSA 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 ssadump.go program if you want a standalone tool
    49  // with similar functionality. It is located at
    50  // github.com/jd-ly/tools/cmd/ssadump.
    51  //
    52  func 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 SSA program.
    67  	hello, _, err := ssautil.BuildPackage(
    68  		&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.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  	//
    83  	// package hello:
    84  	//   func  init       func()
    85  	//   var   init$guard bool
    86  	//   func  main       func()
    87  	//   const message    message = "Hello, World!":untyped string
    88  	//
    89  	// # Name: hello.init
    90  	// # Package: hello
    91  	// # Synthetic: package initializer
    92  	// func init():
    93  	// 0:                                                                entry P:0 S:2
    94  	// 	t0 = *init$guard                                                   bool
    95  	// 	if t0 goto 2 else 1
    96  	// 1:                                                           init.start P:1 S:1
    97  	// 	*init$guard = true:bool
    98  	// 	t1 = fmt.init()                                                      ()
    99  	// 	jump 2
   100  	// 2:                                                            init.done P:2 S:0
   101  	// 	return
   102  	//
   103  	// # Name: hello.main
   104  	// # Package: hello
   105  	// # Location: hello.go:8:6
   106  	// func main():
   107  	// 0:                                                                entry P:0 S:0
   108  	// 	t0 = new [1]interface{} (varargs)                       *[1]interface{}
   109  	// 	t1 = &t0[0:int]                                            *interface{}
   110  	// 	t2 = make interface{} <- string ("Hello, World!":string)    interface{}
   111  	// 	*t1 = t2
   112  	// 	t3 = slice t0[:]                                          []interface{}
   113  	// 	t4 = fmt.Println(t3...)                              (n int, err error)
   114  	// 	return
   115  }
   116  
   117  // This example builds SSA code for a set of packages using the
   118  // x/tools/go/packages API. This is what you would typically use for a
   119  // analysis capable of operating on a single package.
   120  func Example_loadPackages() {
   121  	// Load, parse, and type-check the initial packages.
   122  	cfg := &packages.Config{Mode: packages.LoadSyntax}
   123  	initial, err := packages.Load(cfg, "fmt", "net/http")
   124  	if err != nil {
   125  		log.Fatal(err)
   126  	}
   127  
   128  	// Stop if any package had errors.
   129  	// This step is optional; without it, the next step
   130  	// will create SSA for only a subset of packages.
   131  	if packages.PrintErrors(initial) > 0 {
   132  		log.Fatalf("packages contain errors")
   133  	}
   134  
   135  	// Create SSA packages for all well-typed packages.
   136  	prog, pkgs := ssautil.Packages(initial, ssa.PrintPackages)
   137  	_ = prog
   138  
   139  	// Build SSA code for the well-typed initial packages.
   140  	for _, p := range pkgs {
   141  		if p != nil {
   142  			p.Build()
   143  		}
   144  	}
   145  }
   146  
   147  // This example builds SSA code for a set of packages plus all their dependencies,
   148  // using the x/tools/go/packages API.
   149  // This is what you'd typically use for a whole-program analysis.
   150  func Example_loadWholeProgram() {
   151  	// Load, parse, and type-check the whole program.
   152  	cfg := packages.Config{Mode: packages.LoadAllSyntax}
   153  	initial, err := packages.Load(&cfg, "fmt", "net/http")
   154  	if err != nil {
   155  		log.Fatal(err)
   156  	}
   157  
   158  	// Create SSA packages for well-typed packages and their dependencies.
   159  	prog, pkgs := ssautil.AllPackages(initial, ssa.PrintPackages)
   160  	_ = pkgs
   161  
   162  	// Build SSA code for the whole program.
   163  	prog.Build()
   164  }