github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/gcexportdata/example_test.go (about)

     1  // Copyright 2016 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 go1.7 && gc && !android && !ios && !js
     6  // +build go1.7,gc,!android,!ios,!js
     7  
     8  package gcexportdata_test
     9  
    10  import (
    11  	"fmt"
    12  	"go/ast"
    13  	"go/parser"
    14  	"go/token"
    15  	"go/types"
    16  	"log"
    17  	"os"
    18  	"path/filepath"
    19  	"strings"
    20  
    21  	"golang.org/x/tools/go/gcexportdata"
    22  )
    23  
    24  // ExampleRead uses gcexportdata.Read to load type information for the
    25  // "fmt" package from the fmt.a file produced by the gc compiler.
    26  func ExampleRead() {
    27  	// Find the export data file.
    28  	filename, path := gcexportdata.Find("fmt", "")
    29  	if filename == "" {
    30  		log.Fatalf("can't find export data for fmt")
    31  	}
    32  	fmt.Printf("Package path:       %s\n", path)
    33  
    34  	// Open and read the file.
    35  	f, err := os.Open(filename)
    36  	if err != nil {
    37  		log.Fatal(err)
    38  	}
    39  	defer f.Close()
    40  	r, err := gcexportdata.NewReader(f)
    41  	if err != nil {
    42  		log.Fatalf("reading export data %s: %v", filename, err)
    43  	}
    44  
    45  	// Decode the export data.
    46  	fset := token.NewFileSet()
    47  	imports := make(map[string]*types.Package)
    48  	pkg, err := gcexportdata.Read(r, fset, imports, path)
    49  	if err != nil {
    50  		log.Fatal(err)
    51  	}
    52  
    53  	// We can see all the names in Names.
    54  	members := pkg.Scope().Names()
    55  	foundPrintln := false
    56  	for _, member := range members {
    57  		if member == "Println" {
    58  			foundPrintln = true
    59  			break
    60  		}
    61  	}
    62  	fmt.Print("Package members:    ")
    63  	if foundPrintln {
    64  		fmt.Println("Println found")
    65  	} else {
    66  		fmt.Println("Println not found")
    67  	}
    68  
    69  	// We can also look up a name directly using Lookup.
    70  	println := pkg.Scope().Lookup("Println")
    71  	// go 1.18+ uses the 'any' alias
    72  	typ := strings.ReplaceAll(println.Type().String(), "interface{}", "any")
    73  	fmt.Printf("Println type:       %s\n", typ)
    74  	posn := fset.Position(println.Pos())
    75  	// make example deterministic
    76  	posn.Line = 123
    77  	fmt.Printf("Println location:   %s\n", slashify(posn))
    78  
    79  	// Output:
    80  	//
    81  	// Package path:       fmt
    82  	// Package members:    Println found
    83  	// Println type:       func(a ...any) (n int, err error)
    84  	// Println location:   $GOROOT/src/fmt/print.go:123:1
    85  }
    86  
    87  // ExampleNewImporter demonstrates usage of NewImporter to provide type
    88  // information for dependencies when type-checking Go source code.
    89  func ExampleNewImporter() {
    90  	const src = `package myrpc
    91  
    92  // choosing a package that doesn't change across releases
    93  import "net/rpc"
    94  
    95  const serverError rpc.ServerError = ""
    96  `
    97  	fset := token.NewFileSet()
    98  	f, err := parser.ParseFile(fset, "myrpc.go", src, 0)
    99  	if err != nil {
   100  		log.Fatal(err)
   101  	}
   102  
   103  	packages := make(map[string]*types.Package)
   104  	imp := gcexportdata.NewImporter(fset, packages)
   105  	conf := types.Config{Importer: imp}
   106  	pkg, err := conf.Check("myrpc", fset, []*ast.File{f}, nil)
   107  	if err != nil {
   108  		log.Fatal(err)
   109  	}
   110  
   111  	// object from imported package
   112  	pi := packages["net/rpc"].Scope().Lookup("ServerError")
   113  	fmt.Printf("type %s.%s %s // %s\n",
   114  		pi.Pkg().Path(),
   115  		pi.Name(),
   116  		pi.Type().Underlying(),
   117  		slashify(fset.Position(pi.Pos())),
   118  	)
   119  
   120  	// object in source package
   121  	twopi := pkg.Scope().Lookup("serverError")
   122  	fmt.Printf("const %s %s = %s // %s\n",
   123  		twopi.Name(),
   124  		twopi.Type(),
   125  		twopi.(*types.Const).Val(),
   126  		slashify(fset.Position(twopi.Pos())),
   127  	)
   128  
   129  	// Output:
   130  	//
   131  	// type net/rpc.ServerError string // $GOROOT/src/net/rpc/client.go:20:1
   132  	// const serverError net/rpc.ServerError = "" // myrpc.go:6:7
   133  }
   134  
   135  func slashify(posn token.Position) token.Position {
   136  	posn.Filename = filepath.ToSlash(posn.Filename) // for MS Windows portability
   137  	return posn
   138  }