]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: implement Info.PkgNameOf
authorRobert Griesemer <gri@golang.org>
Fri, 10 Nov 2023 18:52:12 +0000 (10:52 -0800)
committerGopher Robot <gobot@golang.org>
Sat, 11 Nov 2023 02:02:35 +0000 (02:02 +0000)
For #62037.

Change-Id: I354f6417232708278d3f2b2d5ea41ff48e08d6b6
Reviewed-on: https://go-review.googlesource.com/c/go/+/541575
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>

api/next/62037.txt [new file with mode: 0644]
src/cmd/compile/internal/types2/api.go
src/cmd/compile/internal/types2/api_test.go
src/go/types/api.go
src/go/types/api_test.go

diff --git a/api/next/62037.txt b/api/next/62037.txt
new file mode 100644 (file)
index 0000000..7837421
--- /dev/null
@@ -0,0 +1,2 @@
+pkg go/types, method (*Info) PkgNameOf(*ast.ImportSpec) *PkgName #62037
+pkg go/types, method (Checker) PkgNameOf(*ast.ImportSpec) *PkgName #62037
index 675882c49f1b8d874e6355d8b9b6cd322e33be8c..2093ceb817a01bd0532ed2be61c14353501ea9b0 100644 (file)
@@ -342,6 +342,23 @@ func (info *Info) ObjectOf(id *syntax.Name) Object {
        return info.Uses[id]
 }
 
+// PkgNameOf returns the local package name defined by the import,
+// or nil if not found.
+//
+// For dot-imports, the package name is ".".
+//
+// Precondition: the Defs and Implicts maps are populated.
+func (info *Info) PkgNameOf(imp *syntax.ImportDecl) *PkgName {
+       var obj Object
+       if imp.LocalPkgName != nil {
+               obj = info.Defs[imp.LocalPkgName]
+       } else {
+               obj = info.Implicits[imp]
+       }
+       pkgname, _ := obj.(*PkgName)
+       return pkgname
+}
+
 // TypeAndValue reports the type and value (for constants)
 // of the corresponding expression.
 type TypeAndValue struct {
index f5bdcf213daf14b2b319272974306deac23400d1..a2621854bc4a1743cd2d6befeb7e5ecf03fbf92c 100644 (file)
@@ -958,6 +958,80 @@ func TestImplicitsInfo(t *testing.T) {
        }
 }
 
+func TestPkgNameOf(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src = `
+package p
+
+import (
+       . "os"
+       _ "io"
+       "math"
+       "path/filepath"
+       snort "sort"
+)
+
+// avoid imported and not used errors
+var (
+       _ = Open // os.Open
+       _ = math.Sin
+       _ = filepath.Abs
+       _ = snort.Ints
+)
+`
+
+       var tests = []struct {
+               path string // path string enclosed in "'s
+               want string
+       }{
+               {`"os"`, "."},
+               {`"io"`, "_"},
+               {`"math"`, "math"},
+               {`"path/filepath"`, "filepath"},
+               {`"sort"`, "snort"},
+       }
+
+       f := mustParse(src)
+       info := Info{
+               Defs:      make(map[*syntax.Name]Object),
+               Implicits: make(map[syntax.Node]Object),
+       }
+       var conf Config
+       conf.Importer = defaultImporter()
+       _, err := conf.Check("p", []*syntax.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // map import paths to importDecl
+       imports := make(map[string]*syntax.ImportDecl)
+       for _, d := range f.DeclList {
+               if imp, _ := d.(*syntax.ImportDecl); imp != nil {
+                       imports[imp.Path.Value] = imp
+               }
+       }
+
+       for _, test := range tests {
+               imp := imports[test.path]
+               if imp == nil {
+                       t.Fatalf("invalid test case: import path %s not found", test.path)
+               }
+               got := info.PkgNameOf(imp)
+               if got == nil {
+                       t.Fatalf("import %s: package name not found", test.path)
+               }
+               if got.Name() != test.want {
+                       t.Errorf("import %s: got %s; want %s", test.path, got.Name(), test.want)
+               }
+       }
+
+       // test non-existing importDecl
+       if got := info.PkgNameOf(new(syntax.ImportDecl)); got != nil {
+               t.Errorf("got %s for non-existing import declaration", got.Name())
+       }
+}
+
 func predString(tv TypeAndValue) string {
        var buf strings.Builder
        pred := func(b bool, s string) {
index 38cde80085897f61bb6413ba70a090a083242566..0dc06af53843361a813a1fbe92614f4b4461e904 100644 (file)
@@ -331,6 +331,23 @@ func (info *Info) ObjectOf(id *ast.Ident) Object {
        return info.Uses[id]
 }
 
+// PkgNameOf returns the local package name defined by the import,
+// or nil if not found.
+//
+// For dot-imports, the package name is ".".
+//
+// Precondition: the Defs and Implicts maps are populated.
+func (info *Info) PkgNameOf(imp *ast.ImportSpec) *PkgName {
+       var obj Object
+       if imp.Name != nil {
+               obj = info.Defs[imp.Name]
+       } else {
+               obj = info.Implicits[imp]
+       }
+       pkgname, _ := obj.(*PkgName)
+       return pkgname
+}
+
 // TypeAndValue reports the type and value (for constants)
 // of the corresponding expression.
 type TypeAndValue struct {
index 0769890101caf02c40303ae66c6d319fa020839f..3050b930b5d692c551d6bd881bd311347a656b61 100644 (file)
@@ -960,6 +960,81 @@ func TestImplicitsInfo(t *testing.T) {
        }
 }
 
+func TestPkgNameOf(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+
+       const src = `
+package p
+
+import (
+       . "os"
+       _ "io"
+       "math"
+       "path/filepath"
+       snort "sort"
+)
+
+// avoid imported and not used errors
+var (
+       _ = Open // os.Open
+       _ = math.Sin
+       _ = filepath.Abs
+       _ = snort.Ints
+)
+`
+
+       var tests = []struct {
+               path string // path string enclosed in "'s
+               want string
+       }{
+               {`"os"`, "."},
+               {`"io"`, "_"},
+               {`"math"`, "math"},
+               {`"path/filepath"`, "filepath"},
+               {`"sort"`, "snort"},
+       }
+
+       fset := token.NewFileSet()
+       f := mustParse(fset, src)
+       info := Info{
+               Defs:      make(map[*ast.Ident]Object),
+               Implicits: make(map[ast.Node]Object),
+       }
+       var conf Config
+       conf.Importer = importer.Default()
+       _, err := conf.Check("p", fset, []*ast.File{f}, &info)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       // map import paths to importDecl
+       imports := make(map[string]*ast.ImportSpec)
+       for _, s := range f.Decls[0].(*ast.GenDecl).Specs {
+               if imp, _ := s.(*ast.ImportSpec); imp != nil {
+                       imports[imp.Path.Value] = imp
+               }
+       }
+
+       for _, test := range tests {
+               imp := imports[test.path]
+               if imp == nil {
+                       t.Fatalf("invalid test case: import path %s not found", test.path)
+               }
+               got := info.PkgNameOf(imp)
+               if got == nil {
+                       t.Fatalf("import %s: package name not found", test.path)
+               }
+               if got.Name() != test.want {
+                       t.Errorf("import %s: got %s; want %s", test.path, got.Name(), test.want)
+               }
+       }
+
+       // test non-existing importDecl
+       if got := info.PkgNameOf(new(ast.ImportSpec)); got != nil {
+               t.Errorf("got %s for non-existing import declaration", got.Name())
+       }
+}
+
 func predString(tv TypeAndValue) string {
        var buf strings.Builder
        pred := func(b bool, s string) {