github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/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/powerman/golang-tools/go/packages"
    18  	"github.com/powerman/golang-tools/go/ssa"
    19  	"github.com/powerman/golang-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/powerman/golang-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/powerman/golang-tools/cmd/ssadump.
    51  //
    52  func Example_buildPackage() {
    53  	// Replace interface{} with any for this test.
    54  	ssa.SetNormalizeAnyForTesting(true)
    55  	defer ssa.SetNormalizeAnyForTesting(false)
    56  	// Parse the source files.
    57  	fset := token.NewFileSet()
    58  	f, err := parser.ParseFile(fset, "hello.go", hello, parser.ParseComments)
    59  	if err != nil {
    60  		fmt.Print(err) // parse error
    61  		return
    62  	}
    63  	files := []*ast.File{f}
    64  
    65  	// Create the type-checker's package.
    66  	pkg := types.NewPackage("hello", "")
    67  
    68  	// Type-check the package, load dependencies.
    69  	// Create and build the SSA program.
    70  	hello, _, err := ssautil.BuildPackage(
    71  		&types.Config{Importer: importer.Default()}, fset, pkg, files, ssa.SanityCheckFunctions)
    72  	if err != nil {
    73  		fmt.Print(err) // type error in some package
    74  		return
    75  	}
    76  
    77  	// Print out the package.
    78  	hello.WriteTo(os.Stdout)
    79  
    80  	// Print out the package-level functions.
    81  	hello.Func("init").WriteTo(os.Stdout)
    82  	hello.Func("main").WriteTo(os.Stdout)
    83  
    84  	// Output:
    85  	//
    86  	// package hello:
    87  	//   func  init       func()
    88  	//   var   init$guard bool
    89  	//   func  main       func()
    90  	//   const message    message = "Hello, World!":untyped string
    91  	//
    92  	// # Name: hello.init
    93  	// # Package: hello
    94  	// # Synthetic: package initializer
    95  	// func init():
    96  	// 0:                                                                entry P:0 S:2
    97  	// 	t0 = *init$guard                                                   bool
    98  	// 	if t0 goto 2 else 1
    99  	// 1:                                                           init.start P:1 S:1
   100  	// 	*init$guard = true:bool
   101  	// 	t1 = fmt.init()                                                      ()
   102  	// 	jump 2
   103  	// 2:                                                            init.done P:2 S:0
   104  	// 	return
   105  	//
   106  	// # Name: hello.main
   107  	// # Package: hello
   108  	// # Location: hello.go:8:6
   109  	// func main():
   110  	// 0:                                                                entry P:0 S:0
   111  	// 	t0 = new [1]any (varargs)                                       *[1]any
   112  	// 	t1 = &t0[0:int]                                                    *any
   113  	// 	t2 = make any <- string ("Hello, World!":string)                    any
   114  	// 	*t1 = t2
   115  	// 	t3 = slice t0[:]                                                  []any
   116  	// 	t4 = fmt.Println(t3...)                              (n int, err error)
   117  	// 	return
   118  }
   119  
   120  // This example builds SSA code for a set of packages using the
   121  // x/tools/go/packages API. This is what you would typically use for a
   122  // analysis capable of operating on a single package.
   123  func Example_loadPackages() {
   124  	// Load, parse, and type-check the initial packages.
   125  	cfg := &packages.Config{Mode: packages.LoadSyntax}
   126  	initial, err := packages.Load(cfg, "fmt", "net/http")
   127  	if err != nil {
   128  		log.Fatal(err)
   129  	}
   130  
   131  	// Stop if any package had errors.
   132  	// This step is optional; without it, the next step
   133  	// will create SSA for only a subset of packages.
   134  	if packages.PrintErrors(initial) > 0 {
   135  		log.Fatalf("packages contain errors")
   136  	}
   137  
   138  	// Create SSA packages for all well-typed packages.
   139  	prog, pkgs := ssautil.Packages(initial, ssa.PrintPackages)
   140  	_ = prog
   141  
   142  	// Build SSA code for the well-typed initial packages.
   143  	for _, p := range pkgs {
   144  		if p != nil {
   145  			p.Build()
   146  		}
   147  	}
   148  }
   149  
   150  // This example builds SSA code for a set of packages plus all their dependencies,
   151  // using the x/tools/go/packages API.
   152  // This is what you'd typically use for a whole-program analysis.
   153  func Example_loadWholeProgram() {
   154  	// Load, parse, and type-check the whole program.
   155  	cfg := packages.Config{Mode: packages.LoadAllSyntax}
   156  	initial, err := packages.Load(&cfg, "fmt", "net/http")
   157  	if err != nil {
   158  		log.Fatal(err)
   159  	}
   160  
   161  	// Create SSA packages for well-typed packages and their dependencies.
   162  	prog, pkgs := ssautil.AllPackages(initial, ssa.PrintPackages)
   163  	_ = pkgs
   164  
   165  	// Build SSA code for the whole program.
   166  	prog.Build()
   167  }