@@ -585,65 +585,128 @@ func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv
585
585
return fixes , nil
586
586
}
587
587
588
- // getAllCandidates gets all of the candidates to be imported, regardless of if they are needed.
589
- func getAllCandidates (filename string , env * ProcessEnv ) ([]ImportFix , error ) {
588
+ // getCandidatePkgs returns the list of pkgs that are accessible from filename,
589
+ // optionall filtered to only packages named pkgName.
590
+ func getCandidatePkgs (pkgName , filename string , env * ProcessEnv ) ([]* pkg , error ) {
590
591
// TODO(heschi): filter out current package. (Don't forget x_test can import x.)
591
592
593
+ var result []* pkg
592
594
// Start off with the standard library.
593
- var imports []ImportFix
594
595
for importPath := range stdlib {
595
- imports = append (imports , ImportFix {
596
- StmtInfo : ImportInfo {
597
- ImportPath : importPath ,
598
- },
599
- IdentName : path .Base (importPath ),
600
- FixType : AddImport ,
596
+ if pkgName != "" && path .Base (importPath ) != pkgName {
597
+ continue
598
+ }
599
+ result = append (result , & pkg {
600
+ dir : filepath .Join (env .GOROOT , "src" , importPath ),
601
+ importPathShort : importPath ,
602
+ packageName : path .Base (importPath ),
603
+ relevance : 0 ,
601
604
})
602
605
}
603
- // Sort the stdlib bits solely by name.
604
- sort .Slice (imports , func (i int , j int ) bool {
605
- return imports [i ].StmtInfo .ImportPath < imports [j ].StmtInfo .ImportPath
606
- })
607
606
608
607
// Exclude goroot results -- getting them is relatively expensive, not cached,
609
608
// and generally redundant with the in-memory version.
610
609
exclude := []gopathwalk.RootType {gopathwalk .RootGOROOT }
611
610
// Only the go/packages resolver uses the first argument, and nobody uses that resolver.
612
- pkgs , err := env .GetResolver ().scan (nil , true , exclude )
611
+ scannedPkgs , err := env .GetResolver ().scan (nil , true , exclude )
613
612
if err != nil {
614
613
return nil , err
615
614
}
616
- // Sort first by relevance, then by name, so that when we add them they're
617
- // still in order.
618
- sort .Slice (pkgs , func (i , j int ) bool {
619
- pi , pj := pkgs [i ], pkgs [j ]
620
- if pi .relevance < pj .relevance {
621
- return true
622
- }
623
- if pi .relevance > pj .relevance {
624
- return false
625
- }
626
- return pi .packageName < pj .packageName
627
- })
628
615
629
616
dupCheck := map [string ]struct {}{}
630
- for _ , pkg := range pkgs {
617
+ for _ , pkg := range scannedPkgs {
618
+ if pkgName != "" && pkg .packageName != pkgName {
619
+ continue
620
+ }
631
621
if ! canUse (filename , pkg .dir ) {
632
622
continue
633
623
}
634
624
if _ , ok := dupCheck [pkg .importPathShort ]; ok {
635
625
continue
636
626
}
637
627
dupCheck [pkg .importPathShort ] = struct {}{}
638
- imports = append (imports , ImportFix {
628
+ result = append (result , pkg )
629
+ }
630
+
631
+ // Sort first by relevance, then by package name, with import path as a tiebreaker.
632
+ sort .Slice (result , func (i , j int ) bool {
633
+ pi , pj := result [i ], result [j ]
634
+ if pi .relevance != pj .relevance {
635
+ return pi .relevance < pj .relevance
636
+ }
637
+ if pi .packageName != pj .packageName {
638
+ return pi .packageName < pj .packageName
639
+ }
640
+ return pi .importPathShort < pj .importPathShort
641
+ })
642
+
643
+ return result , nil
644
+ }
645
+
646
+ // getAllCandidates gets all of the candidates to be imported, regardless of if they are needed.
647
+ func getAllCandidates (filename string , env * ProcessEnv ) ([]ImportFix , error ) {
648
+ pkgs , err := getCandidatePkgs ("" , filename , env )
649
+ if err != nil {
650
+ return nil , err
651
+ }
652
+ result := make ([]ImportFix , 0 , len (pkgs ))
653
+ for _ , pkg := range pkgs {
654
+ result = append (result , ImportFix {
655
+ StmtInfo : ImportInfo {
656
+ ImportPath : pkg .importPathShort ,
657
+ },
658
+ IdentName : pkg .packageName ,
659
+ FixType : AddImport ,
660
+ })
661
+ }
662
+ return result , nil
663
+ }
664
+
665
+ // A PackageExport is a package and its exports.
666
+ type PackageExport struct {
667
+ Fix * ImportFix
668
+ Exports []string
669
+ }
670
+
671
+ func getPackageExports (completePackage , filename string , env * ProcessEnv ) ([]PackageExport , error ) {
672
+ pkgs , err := getCandidatePkgs (completePackage , filename , env )
673
+ if err != nil {
674
+ return nil , err
675
+ }
676
+
677
+ results := make ([]PackageExport , 0 , len (pkgs ))
678
+ for _ , pkg := range pkgs {
679
+ fix := & ImportFix {
639
680
StmtInfo : ImportInfo {
640
681
ImportPath : pkg .importPathShort ,
641
682
},
642
683
IdentName : pkg .packageName ,
643
684
FixType : AddImport ,
685
+ }
686
+ var exportsMap map [string ]bool
687
+ if e , ok := stdlib [pkg .importPathShort ]; ok {
688
+ exportsMap = e
689
+ } else {
690
+ exportsMap , err = env .GetResolver ().loadExports (context .TODO (), completePackage , pkg )
691
+ if err != nil {
692
+ if env .Debug {
693
+ env .Logf ("while completing %q, error loading exports from %q: %v" , completePackage , pkg .importPathShort , err )
694
+ }
695
+ continue
696
+ }
697
+ }
698
+ var exports []string
699
+ for export := range exportsMap {
700
+ exports = append (exports , export )
701
+ }
702
+ sort .Strings (exports )
703
+ results = append (results , PackageExport {
704
+ Fix : fix ,
705
+ Exports : exports ,
644
706
})
645
707
}
646
- return imports , nil
708
+
709
+ return results , nil
647
710
}
648
711
649
712
// ProcessEnv contains environment variables and settings that affect the use of
0 commit comments