mirror of
https://github.com/golang/go
synced 2024-10-03 23:21:22 -06:00
exp/types: testing resolution of qualified identifiers
Also: fix a bug with exp/types/GcImport. R=rsc, r CC=golang-dev https://golang.org/cl/6302060
This commit is contained in:
parent
d608b15db7
commit
49d6e49087
@ -89,10 +89,6 @@ func GcImportData(imports map[string]*ast.Object, filename, id string, data *buf
|
|||||||
fmt.Printf("importing %s (%s)\n", id, filename)
|
fmt.Printf("importing %s (%s)\n", id, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if imports[id] != nil {
|
|
||||||
panic(fmt.Sprintf("package %s already imported", id))
|
|
||||||
}
|
|
||||||
|
|
||||||
// support for gcParser error handling
|
// support for gcParser error handling
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -128,9 +124,12 @@ func GcImport(imports map[string]*ast.Object, path string) (pkg *ast.Object, err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg = imports[id]; pkg != nil {
|
// Note: imports[id] may already contain a partially imported package.
|
||||||
return // package was imported before
|
// We must continue doing the full import here since we don't
|
||||||
}
|
// know if something is missing.
|
||||||
|
// TODO: There's no need to re-import a package if we know that we
|
||||||
|
// have done a full import before. At the moment we cannot
|
||||||
|
// tell from the available information in this function alone.
|
||||||
|
|
||||||
// open file
|
// open file
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
@ -294,9 +293,8 @@ func (p *gcParser) parsePkgId() *ast.Object {
|
|||||||
|
|
||||||
pkg := p.imports[id]
|
pkg := p.imports[id]
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
scope = ast.NewScope(nil)
|
|
||||||
pkg = ast.NewObj(ast.Pkg, "")
|
pkg = ast.NewObj(ast.Pkg, "")
|
||||||
pkg.Data = scope
|
pkg.Data = ast.NewScope(nil)
|
||||||
p.imports[id] = pkg
|
p.imports[id] = pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -867,10 +865,12 @@ func (p *gcParser) parseExport() *ast.Object {
|
|||||||
}
|
}
|
||||||
p.expect('\n')
|
p.expect('\n')
|
||||||
|
|
||||||
assert(p.imports[p.id] == nil)
|
pkg := p.imports[p.id]
|
||||||
pkg := ast.NewObj(ast.Pkg, name)
|
if pkg == nil {
|
||||||
pkg.Data = ast.NewScope(nil)
|
pkg = ast.NewObj(ast.Pkg, name)
|
||||||
p.imports[p.id] = pkg
|
pkg.Data = ast.NewScope(nil)
|
||||||
|
p.imports[p.id] = pkg
|
||||||
|
}
|
||||||
|
|
||||||
for p.tok != '$' && p.tok != scanner.EOF {
|
for p.tok != '$' && p.tok != scanner.EOF {
|
||||||
p.parseDecl()
|
p.parseDecl()
|
||||||
|
130
src/pkg/exp/types/resolver_test.go
Normal file
130
src/pkg/exp/types/resolver_test.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/scanner"
|
||||||
|
"go/token"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sources = []string{
|
||||||
|
`package p
|
||||||
|
import "fmt"
|
||||||
|
import "math"
|
||||||
|
const pi = math.Pi
|
||||||
|
func sin(x float64) float64 {
|
||||||
|
return math.Sin(x)
|
||||||
|
}
|
||||||
|
var Println = fmt.Println
|
||||||
|
`,
|
||||||
|
`package p
|
||||||
|
import "fmt"
|
||||||
|
func f() string {
|
||||||
|
return fmt.Sprintf("%d", g())
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
`package p
|
||||||
|
import . "go/parser"
|
||||||
|
func g() Mode { return ImportsOnly }`,
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgnames = []string{
|
||||||
|
"fmt",
|
||||||
|
"go/parser",
|
||||||
|
"math",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveQualifiedIdents resolves the selectors of qualified
|
||||||
|
// identifiers by associating the correct ast.Object with them.
|
||||||
|
// TODO(gri): Eventually, this functionality should be subsumed
|
||||||
|
// by Check.
|
||||||
|
//
|
||||||
|
func ResolveQualifiedIdents(fset *token.FileSet, pkg *ast.Package) error {
|
||||||
|
var errors scanner.ErrorList
|
||||||
|
|
||||||
|
findObj := func(pkg *ast.Object, name *ast.Ident) *ast.Object {
|
||||||
|
scope := pkg.Data.(*ast.Scope)
|
||||||
|
obj := scope.Lookup(name.Name)
|
||||||
|
if obj == nil {
|
||||||
|
errors.Add(fset.Position(name.Pos()), fmt.Sprintf("no %s in package %s", name.Name, pkg.Name))
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
ast.Inspect(pkg, func(n ast.Node) bool {
|
||||||
|
if s, ok := n.(*ast.SelectorExpr); ok {
|
||||||
|
if x, ok := s.X.(*ast.Ident); ok && x.Obj != nil && x.Obj.Kind == ast.Pkg {
|
||||||
|
// find selector in respective package
|
||||||
|
s.Sel.Obj = findObj(x.Obj, s.Sel)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return errors.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveQualifiedIdents(t *testing.T) {
|
||||||
|
// parse package files
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
files := make(map[string]*ast.File)
|
||||||
|
for i, src := range sources {
|
||||||
|
filename := fmt.Sprintf("file%d", i)
|
||||||
|
f, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
files[filename] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve package AST
|
||||||
|
pkg, err := ast.NewPackage(fset, files, GcImport, Universe)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that all packages were imported
|
||||||
|
for _, name := range pkgnames {
|
||||||
|
if pkg.Imports[name] == nil {
|
||||||
|
t.Errorf("package %s not imported", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that there are no top-level unresolved identifiers
|
||||||
|
for _, f := range pkg.Files {
|
||||||
|
for _, x := range f.Unresolved {
|
||||||
|
t.Errorf("%s: unresolved global identifier %s", fset.Position(x.Pos()), x.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve qualified identifiers
|
||||||
|
if err := ResolveQualifiedIdents(fset, pkg); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that qualified identifiers are resolved
|
||||||
|
ast.Inspect(pkg, func(n ast.Node) bool {
|
||||||
|
if s, ok := n.(*ast.SelectorExpr); ok {
|
||||||
|
if x, ok := s.X.(*ast.Ident); ok {
|
||||||
|
if x.Obj == nil {
|
||||||
|
t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if x.Obj.Kind == ast.Pkg && s.Sel != nil && s.Sel.Obj == nil {
|
||||||
|
t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user