...

Source file src/golang.org/x/tools/go/ssa/example_test.go

Documentation: golang.org/x/tools/go/ssa

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

View as plain text