github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/ssa/create.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  // +build go1.5
     6  
     7  package ssa
     8  
     9  // This file implements the CREATE phase of SSA construction.
    10  // See builder.go for explanation.
    11  
    12  import (
    13  	"fmt"
    14  	"go/ast"
    15  	"go/token"
    16  	"go/types"
    17  	"os"
    18  	"sync"
    19  
    20  	"golang.org/x/tools/go/types/typeutil"
    21  )
    22  
    23  // NewProgram returns a new SSA Program.
    24  //
    25  // mode controls diagnostics and checking during SSA construction.
    26  //
    27  func NewProgram(fset *token.FileSet, mode BuilderMode) *Program {
    28  	prog := &Program{
    29  		Fset:     fset,
    30  		imported: make(map[string]*Package),
    31  		packages: make(map[*types.Package]*Package),
    32  		thunks:   make(map[selectionKey]*Function),
    33  		bounds:   make(map[*types.Func]*Function),
    34  		mode:     mode,
    35  	}
    36  
    37  	h := typeutil.MakeHasher() // protected by methodsMu, in effect
    38  	prog.methodSets.SetHasher(h)
    39  	prog.canon.SetHasher(h)
    40  
    41  	return prog
    42  }
    43  
    44  // memberFromObject populates package pkg with a member for the
    45  // typechecker object obj.
    46  //
    47  // For objects from Go source code, syntax is the associated syntax
    48  // tree (for funcs and vars only); it will be used during the build
    49  // phase.
    50  //
    51  func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
    52  	name := obj.Name()
    53  	switch obj := obj.(type) {
    54  	case *types.TypeName:
    55  		pkg.Members[name] = &Type{
    56  			object: obj,
    57  			pkg:    pkg,
    58  		}
    59  
    60  	case *types.Const:
    61  		c := &NamedConst{
    62  			object: obj,
    63  			Value:  NewConst(obj.Val(), obj.Type()),
    64  			pkg:    pkg,
    65  		}
    66  		pkg.values[obj] = c.Value
    67  		pkg.Members[name] = c
    68  
    69  	case *types.Var:
    70  		g := &Global{
    71  			Pkg:    pkg,
    72  			name:   name,
    73  			object: obj,
    74  			typ:    types.NewPointer(obj.Type()), // address
    75  			pos:    obj.Pos(),
    76  		}
    77  		pkg.values[obj] = g
    78  		pkg.Members[name] = g
    79  
    80  	case *types.Func:
    81  		sig := obj.Type().(*types.Signature)
    82  		if sig.Recv() == nil && name == "init" {
    83  			pkg.ninit++
    84  			name = fmt.Sprintf("init#%d", pkg.ninit)
    85  		}
    86  		fn := &Function{
    87  			name:      name,
    88  			object:    obj,
    89  			Signature: sig,
    90  			syntax:    syntax,
    91  			pos:       obj.Pos(),
    92  			Pkg:       pkg,
    93  			Prog:      pkg.Prog,
    94  		}
    95  		if syntax == nil {
    96  			fn.Synthetic = "loaded from gc object file"
    97  		}
    98  
    99  		pkg.values[obj] = fn
   100  		if sig.Recv() == nil {
   101  			pkg.Members[name] = fn // package-level function
   102  		}
   103  
   104  	default: // (incl. *types.Package)
   105  		panic("unexpected Object type: " + obj.String())
   106  	}
   107  }
   108  
   109  // membersFromDecl populates package pkg with members for each
   110  // typechecker object (var, func, const or type) associated with the
   111  // specified decl.
   112  //
   113  func membersFromDecl(pkg *Package, decl ast.Decl) {
   114  	switch decl := decl.(type) {
   115  	case *ast.GenDecl: // import, const, type or var
   116  		switch decl.Tok {
   117  		case token.CONST:
   118  			for _, spec := range decl.Specs {
   119  				for _, id := range spec.(*ast.ValueSpec).Names {
   120  					if !isBlankIdent(id) {
   121  						memberFromObject(pkg, pkg.info.Defs[id], nil)
   122  					}
   123  				}
   124  			}
   125  
   126  		case token.VAR:
   127  			for _, spec := range decl.Specs {
   128  				for _, id := range spec.(*ast.ValueSpec).Names {
   129  					if !isBlankIdent(id) {
   130  						memberFromObject(pkg, pkg.info.Defs[id], spec)
   131  					}
   132  				}
   133  			}
   134  
   135  		case token.TYPE:
   136  			for _, spec := range decl.Specs {
   137  				id := spec.(*ast.TypeSpec).Name
   138  				if !isBlankIdent(id) {
   139  					memberFromObject(pkg, pkg.info.Defs[id], nil)
   140  				}
   141  			}
   142  		}
   143  
   144  	case *ast.FuncDecl:
   145  		id := decl.Name
   146  		if !isBlankIdent(id) {
   147  			memberFromObject(pkg, pkg.info.Defs[id], decl)
   148  		}
   149  	}
   150  }
   151  
   152  // CreatePackage constructs and returns an SSA Package from the
   153  // specified type-checked, error-free file ASTs, and populates its
   154  // Members mapping.
   155  //
   156  // importable determines whether this package should be returned by a
   157  // subsequent call to ImportedPackage(pkg.Path()).
   158  //
   159  // The real work of building SSA form for each function is not done
   160  // until a subsequent call to Package.Build().
   161  //
   162  func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *types.Info, importable bool) *Package {
   163  	p := &Package{
   164  		Prog:    prog,
   165  		Members: make(map[string]Member),
   166  		values:  make(map[types.Object]Value),
   167  		Pkg:     pkg,
   168  		info:    info,  // transient (CREATE and BUILD phases)
   169  		files:   files, // transient (CREATE and BUILD phases)
   170  	}
   171  
   172  	// Add init() function.
   173  	p.init = &Function{
   174  		name:      "init",
   175  		Signature: new(types.Signature),
   176  		Synthetic: "package initializer",
   177  		Pkg:       p,
   178  		Prog:      prog,
   179  	}
   180  	p.Members[p.init.name] = p.init
   181  
   182  	// CREATE phase.
   183  	// Allocate all package members: vars, funcs, consts and types.
   184  	if len(files) > 0 {
   185  		// Go source package.
   186  		for _, file := range files {
   187  			for _, decl := range file.Decls {
   188  				membersFromDecl(p, decl)
   189  			}
   190  		}
   191  	} else {
   192  		// GC-compiled binary package.
   193  		// No code.
   194  		// No position information.
   195  		scope := p.Pkg.Scope()
   196  		for _, name := range scope.Names() {
   197  			obj := scope.Lookup(name)
   198  			memberFromObject(p, obj, nil)
   199  			if obj, ok := obj.(*types.TypeName); ok {
   200  				named := obj.Type().(*types.Named)
   201  				for i, n := 0, named.NumMethods(); i < n; i++ {
   202  					memberFromObject(p, named.Method(i), nil)
   203  				}
   204  			}
   205  		}
   206  	}
   207  
   208  	if prog.mode&BareInits == 0 {
   209  		// Add initializer guard variable.
   210  		initguard := &Global{
   211  			Pkg:  p,
   212  			name: "init$guard",
   213  			typ:  types.NewPointer(tBool),
   214  		}
   215  		p.Members[initguard.Name()] = initguard
   216  	}
   217  
   218  	if prog.mode&GlobalDebug != 0 {
   219  		p.SetDebugMode(true)
   220  	}
   221  
   222  	if prog.mode&PrintPackages != 0 {
   223  		printMu.Lock()
   224  		p.WriteTo(os.Stdout)
   225  		printMu.Unlock()
   226  	}
   227  
   228  	if importable {
   229  		prog.imported[p.Pkg.Path()] = p
   230  	}
   231  	prog.packages[p.Pkg] = p
   232  
   233  	return p
   234  }
   235  
   236  // printMu serializes printing of Packages/Functions to stdout.
   237  var printMu sync.Mutex
   238  
   239  // AllPackages returns a new slice containing all packages in the
   240  // program prog in unspecified order.
   241  //
   242  func (prog *Program) AllPackages() []*Package {
   243  	pkgs := make([]*Package, 0, len(prog.packages))
   244  	for _, pkg := range prog.packages {
   245  		pkgs = append(pkgs, pkg)
   246  	}
   247  	return pkgs
   248  }
   249  
   250  // ImportedPackage returns the importable SSA Package whose import
   251  // path is path, or nil if no such SSA package has been created.
   252  //
   253  // Not all packages are importable.  For example, no import
   254  // declaration can resolve to the x_test package created by 'go test'
   255  // or the ad-hoc main package created 'go build foo.go'.
   256  //
   257  func (prog *Program) ImportedPackage(path string) *Package {
   258  	return prog.imported[path]
   259  }