...

Source file src/golang.org/x/tools/go/analysis/passes/buildssa/buildssa.go

Documentation: golang.org/x/tools/go/analysis/passes/buildssa

     1  // Copyright 2018 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 buildssa defines an Analyzer that constructs the SSA
     6  // representation of an error-free package and returns the set of all
     7  // functions within it. It does not report any diagnostics itself but
     8  // may be used as an input to other analyzers.
     9  //
    10  // THIS INTERFACE IS EXPERIMENTAL AND MAY BE SUBJECT TO INCOMPATIBLE CHANGE.
    11  package buildssa
    12  
    13  import (
    14  	"go/ast"
    15  	"go/types"
    16  	"reflect"
    17  
    18  	"golang.org/x/tools/go/analysis"
    19  	"golang.org/x/tools/go/ssa"
    20  )
    21  
    22  var Analyzer = &analysis.Analyzer{
    23  	Name:       "buildssa",
    24  	Doc:        "build SSA-form IR for later passes",
    25  	Run:        run,
    26  	ResultType: reflect.TypeOf(new(SSA)),
    27  }
    28  
    29  // SSA provides SSA-form intermediate representation for all the
    30  // non-blank source functions in the current package.
    31  type SSA struct {
    32  	Pkg      *ssa.Package
    33  	SrcFuncs []*ssa.Function
    34  }
    35  
    36  func run(pass *analysis.Pass) (interface{}, error) {
    37  	// Plundered from ssautil.BuildPackage.
    38  
    39  	// We must create a new Program for each Package because the
    40  	// analysis API provides no place to hang a Program shared by
    41  	// all Packages. Consequently, SSA Packages and Functions do not
    42  	// have a canonical representation across an analysis session of
    43  	// multiple packages. This is unlikely to be a problem in
    44  	// practice because the analysis API essentially forces all
    45  	// packages to be analysed independently, so any given call to
    46  	// Analysis.Run on a package will see only SSA objects belonging
    47  	// to a single Program.
    48  
    49  	// Some Analyzers may need GlobalDebug, in which case we'll have
    50  	// to set it globally, but let's wait till we need it.
    51  	mode := ssa.BuilderMode(0)
    52  
    53  	prog := ssa.NewProgram(pass.Fset, mode)
    54  
    55  	// Create SSA packages for all imports.
    56  	// Order is not significant.
    57  	created := make(map[*types.Package]bool)
    58  	var createAll func(pkgs []*types.Package)
    59  	createAll = func(pkgs []*types.Package) {
    60  		for _, p := range pkgs {
    61  			if !created[p] {
    62  				created[p] = true
    63  				prog.CreatePackage(p, nil, nil, true)
    64  				createAll(p.Imports())
    65  			}
    66  		}
    67  	}
    68  	createAll(pass.Pkg.Imports())
    69  
    70  	// Create and build the primary package.
    71  	ssapkg := prog.CreatePackage(pass.Pkg, pass.Files, pass.TypesInfo, false)
    72  	ssapkg.Build()
    73  
    74  	// Compute list of source functions, including literals,
    75  	// in source order.
    76  	var funcs []*ssa.Function
    77  	for _, f := range pass.Files {
    78  		for _, decl := range f.Decls {
    79  			if fdecl, ok := decl.(*ast.FuncDecl); ok {
    80  
    81  				// SSA will not build a Function
    82  				// for a FuncDecl named blank.
    83  				// That's arguably too strict but
    84  				// relaxing it would break uniqueness of
    85  				// names of package members.
    86  				if fdecl.Name.Name == "_" {
    87  					continue
    88  				}
    89  
    90  				// (init functions have distinct Func
    91  				// objects named "init" and distinct
    92  				// ssa.Functions named "init#1", ...)
    93  
    94  				fn := pass.TypesInfo.Defs[fdecl.Name].(*types.Func)
    95  				if fn == nil {
    96  					panic(fn)
    97  				}
    98  
    99  				f := ssapkg.Prog.FuncValue(fn)
   100  				if f == nil {
   101  					panic(fn)
   102  				}
   103  
   104  				var addAnons func(f *ssa.Function)
   105  				addAnons = func(f *ssa.Function) {
   106  					funcs = append(funcs, f)
   107  					for _, anon := range f.AnonFuncs {
   108  						addAnons(anon)
   109  					}
   110  				}
   111  				addAnons(f)
   112  			}
   113  		}
   114  	}
   115  
   116  	return &SSA{Pkg: ssapkg, SrcFuncs: funcs}, nil
   117  }
   118  

View as plain text