src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

source_env.go (3275B)


      1 // Copyright 2024 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 imports
      6 
      7 import (
      8 	"context"
      9 	"path/filepath"
     10 	"strings"
     11 	"sync"
     12 
     13 	"golang.org/x/sync/errgroup"
     14 	"golang.org/x/tools/internal/gopathwalk"
     15 )
     16 
     17 // ProcessEnvSource implements the [Source] interface using the legacy
     18 // [ProcessEnv] abstraction.
     19 type ProcessEnvSource struct {
     20 	env      *ProcessEnv
     21 	srcDir   string
     22 	filename string
     23 	pkgName  string
     24 }
     25 
     26 // NewProcessEnvSource returns a [ProcessEnvSource] wrapping the given
     27 // env, to be used for fixing imports in the file with name filename in package
     28 // named pkgName.
     29 func NewProcessEnvSource(env *ProcessEnv, filename, pkgName string) (*ProcessEnvSource, error) {
     30 	abs, err := filepath.Abs(filename)
     31 	if err != nil {
     32 		return nil, err
     33 	}
     34 	srcDir := filepath.Dir(abs)
     35 	return &ProcessEnvSource{
     36 		env:      env,
     37 		srcDir:   srcDir,
     38 		filename: filename,
     39 		pkgName:  pkgName,
     40 	}, nil
     41 }
     42 
     43 func (s *ProcessEnvSource) LoadPackageNames(ctx context.Context, srcDir string, unknown []string) (map[string]string, error) {
     44 	r, err := s.env.GetResolver()
     45 	if err != nil {
     46 		return nil, err
     47 	}
     48 	return r.loadPackageNames(unknown, srcDir)
     49 }
     50 
     51 func (s *ProcessEnvSource) ResolveReferences(ctx context.Context, filename string, refs map[string]map[string]bool) ([]*Result, error) {
     52 	var mu sync.Mutex
     53 	found := make(map[string][]pkgDistance)
     54 	callback := &scanCallback{
     55 		rootFound: func(gopathwalk.Root) bool {
     56 			return true
     57 		},
     58 		dirFound: func(pkg *pkg) bool {
     59 			return pkgIsCandidate(filename, refs, pkg)
     60 		},
     61 		packageNameLoaded: func(pkg *pkg) bool {
     62 			if _, want := refs[pkg.packageName]; !want {
     63 				return false
     64 			}
     65 			if pkg.dir == s.srcDir && s.pkgName == pkg.packageName {
     66 				// The candidate is in the same directory and has the
     67 				// same package name. Don't try to import ourselves.
     68 				return false
     69 			}
     70 			if !CanUse(filename, pkg.dir) {
     71 				return false
     72 			}
     73 			mu.Lock()
     74 			defer mu.Unlock()
     75 			found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(s.srcDir, pkg.dir)})
     76 			return false // We'll do our own loading after we sort.
     77 		},
     78 	}
     79 	resolver, err := s.env.GetResolver()
     80 	if err != nil {
     81 		return nil, err
     82 	}
     83 	if err := resolver.scan(ctx, callback); err != nil {
     84 		return nil, err
     85 	}
     86 
     87 	g, ctx := errgroup.WithContext(ctx)
     88 
     89 	searcher := symbolSearcher{
     90 		logf:        s.env.logf,
     91 		srcDir:      s.srcDir,
     92 		xtest:       strings.HasSuffix(s.pkgName, "_test"),
     93 		loadExports: resolver.loadExports,
     94 	}
     95 
     96 	var resultMu sync.Mutex
     97 	results := make(map[string]*Result, len(refs))
     98 	for pkgName, symbols := range refs {
     99 		g.Go(func() error {
    100 			found, err := searcher.search(ctx, found[pkgName], pkgName, symbols)
    101 			if err != nil {
    102 				return err
    103 			}
    104 			if found == nil {
    105 				return nil // No matching package.
    106 			}
    107 
    108 			imp := &ImportInfo{
    109 				ImportPath: found.importPathShort,
    110 			}
    111 			pkg := &PackageInfo{
    112 				Name:    pkgName,
    113 				Exports: symbols,
    114 			}
    115 			resultMu.Lock()
    116 			results[pkgName] = &Result{Import: imp, Package: pkg}
    117 			resultMu.Unlock()
    118 			return nil
    119 		})
    120 	}
    121 	if err := g.Wait(); err != nil {
    122 		return nil, err
    123 	}
    124 	var ans []*Result
    125 	for _, x := range results {
    126 		ans = append(ans, x)
    127 	}
    128 	return ans, nil
    129 }