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