github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/internal/facts/imports.go (about)

     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 facts
     6  
     7  import (
     8  	"go/types"
     9  
    10  	"golang.org/x/tools/internal/typeparams"
    11  )
    12  
    13  // importMap computes the import map for a package by traversing the
    14  // entire exported API each of its imports.
    15  //
    16  // This is a workaround for the fact that we cannot access the map used
    17  // internally by the types.Importer returned by go/importer. The entries
    18  // in this map are the packages and objects that may be relevant to the
    19  // current analysis unit.
    20  //
    21  // Packages in the map that are only indirectly imported may be
    22  // incomplete (!pkg.Complete()).
    23  //
    24  // TODO(adonovan): opt: compute this information more efficiently
    25  // by obtaining it from the internals of the gcexportdata decoder.
    26  func importMap(imports []*types.Package) map[string]*types.Package {
    27  	objects := make(map[types.Object]bool)
    28  	typs := make(map[types.Type]bool) // Named and TypeParam
    29  	packages := make(map[string]*types.Package)
    30  
    31  	var addObj func(obj types.Object)
    32  	var addType func(T types.Type)
    33  
    34  	addObj = func(obj types.Object) {
    35  		if !objects[obj] {
    36  			objects[obj] = true
    37  			addType(obj.Type())
    38  			if pkg := obj.Pkg(); pkg != nil {
    39  				packages[pkg.Path()] = pkg
    40  			}
    41  		}
    42  	}
    43  
    44  	addType = func(T types.Type) {
    45  		switch T := T.(type) {
    46  		case *types.Basic:
    47  			// nop
    48  		case *types.Named:
    49  			// Remove infinite expansions of *types.Named by always looking at the origin.
    50  			// Some named types with type parameters [that will not type check] have
    51  			// infinite expansions:
    52  			//     type N[T any] struct { F *N[N[T]] }
    53  			// importMap() is called on such types when Analyzer.RunDespiteErrors is true.
    54  			T = typeparams.NamedTypeOrigin(T).(*types.Named)
    55  			if !typs[T] {
    56  				typs[T] = true
    57  				addObj(T.Obj())
    58  				addType(T.Underlying())
    59  				for i := 0; i < T.NumMethods(); i++ {
    60  					addObj(T.Method(i))
    61  				}
    62  				if tparams := typeparams.ForNamed(T); tparams != nil {
    63  					for i := 0; i < tparams.Len(); i++ {
    64  						addType(tparams.At(i))
    65  					}
    66  				}
    67  				if targs := typeparams.NamedTypeArgs(T); targs != nil {
    68  					for i := 0; i < targs.Len(); i++ {
    69  						addType(targs.At(i))
    70  					}
    71  				}
    72  			}
    73  		case *types.Pointer:
    74  			addType(T.Elem())
    75  		case *types.Slice:
    76  			addType(T.Elem())
    77  		case *types.Array:
    78  			addType(T.Elem())
    79  		case *types.Chan:
    80  			addType(T.Elem())
    81  		case *types.Map:
    82  			addType(T.Key())
    83  			addType(T.Elem())
    84  		case *types.Signature:
    85  			addType(T.Params())
    86  			addType(T.Results())
    87  			if tparams := typeparams.ForSignature(T); tparams != nil {
    88  				for i := 0; i < tparams.Len(); i++ {
    89  					addType(tparams.At(i))
    90  				}
    91  			}
    92  		case *types.Struct:
    93  			for i := 0; i < T.NumFields(); i++ {
    94  				addObj(T.Field(i))
    95  			}
    96  		case *types.Tuple:
    97  			for i := 0; i < T.Len(); i++ {
    98  				addObj(T.At(i))
    99  			}
   100  		case *types.Interface:
   101  			for i := 0; i < T.NumMethods(); i++ {
   102  				addObj(T.Method(i))
   103  			}
   104  			for i := 0; i < T.NumEmbeddeds(); i++ {
   105  				addType(T.EmbeddedType(i)) // walk Embedded for implicits
   106  			}
   107  		case *typeparams.Union:
   108  			for i := 0; i < T.Len(); i++ {
   109  				addType(T.Term(i).Type())
   110  			}
   111  		case *typeparams.TypeParam:
   112  			if !typs[T] {
   113  				typs[T] = true
   114  				addObj(T.Obj())
   115  				addType(T.Constraint())
   116  			}
   117  		}
   118  	}
   119  
   120  	for _, imp := range imports {
   121  		packages[imp.Path()] = imp
   122  
   123  		scope := imp.Scope()
   124  		for _, name := range scope.Names() {
   125  			addObj(scope.Lookup(name))
   126  		}
   127  	}
   128  
   129  	return packages
   130  }