mirror of
https://github.com/golang/go
synced 2024-10-01 16:08:33 -06:00
cmd/internal/ld: edit into more idiomatic Go code
Instead of reimplementing chained hash tables, just use maps. Use bool instead of uint8 for variables only set to 0 or 1. Fix parsing of `import foo "foo" // indirect` lines. Previously, this was treated as an import of package path `"foo" // indirect`, which could result in the cycle-detection code failing to detect a cycle because it would be treated as a separate package from `"foo"`. Also, since there are theoretically multiple quoted forms for a package path, use strconv.Unquote to normalize them. Side benefit: Unquote will complain if any trailing comments sneak back in. Aside: For most Go archives, Go package data is only present in the __.PKGDEF member, but unless -u is used, ldpkg is only called on the _go_.6 member. Consequently, importcycles is a no-op when -u isn't used as it has no package data to inspect. Change-Id: I7076cf91a66726a8d9c5676adfea13c5532001fa Reviewed-on: https://go-review.googlesource.com/7002 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
b2f29511dd
commit
717cb74907
@ -9,6 +9,7 @@ import (
|
|||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,42 +38,22 @@ func expandpkg(t0 string, pkg string) string {
|
|||||||
* package import data
|
* package import data
|
||||||
*/
|
*/
|
||||||
type Import struct {
|
type Import struct {
|
||||||
hash *Import // next in hash table
|
prefix string // "type", "var", "func", "const"
|
||||||
prefix string // "type", "var", "func", "const"
|
|
||||||
name string
|
name string
|
||||||
def string
|
def string
|
||||||
file string
|
file string
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
// importmap records type information about imported symbols to detect inconsistencies.
|
||||||
NIHASH = 1024
|
// Entries are keyed by qualified symbol name (e.g., "runtime.Callers" or "net/url.Error").
|
||||||
)
|
var importmap = map[string]*Import{}
|
||||||
|
|
||||||
var ihash [NIHASH]*Import
|
func lookupImport(name string) *Import {
|
||||||
|
if x, ok := importmap[name]; ok {
|
||||||
var nimport int
|
return x
|
||||||
|
|
||||||
func hashstr(name string) int {
|
|
||||||
h := uint32(0)
|
|
||||||
for cp := name; cp != ""; cp = cp[1:] {
|
|
||||||
h = h*1119 + uint32(cp[0])
|
|
||||||
}
|
}
|
||||||
h &= 0xffffff
|
x := &Import{name: name}
|
||||||
return int(h)
|
importmap[name] = x
|
||||||
}
|
|
||||||
|
|
||||||
func ilookup(name string) *Import {
|
|
||||||
h := hashstr(name) % NIHASH
|
|
||||||
for x := ihash[h]; x != nil; x = x.hash {
|
|
||||||
if x.name[0] == name[0] && x.name == name {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x := new(Import)
|
|
||||||
x.name = name
|
|
||||||
x.hash = ihash[h]
|
|
||||||
ihash[h] = x
|
|
||||||
nimport++
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,12 +191,10 @@ func loadpkgdata(file string, pkg string, data string) {
|
|||||||
var prefix string
|
var prefix string
|
||||||
var name string
|
var name string
|
||||||
var def string
|
var def string
|
||||||
var x *Import
|
|
||||||
|
|
||||||
file = file
|
|
||||||
p := data
|
p := data
|
||||||
for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
|
for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
|
||||||
x = ilookup(name)
|
x := lookupImport(name)
|
||||||
if x.prefix == "" {
|
if x.prefix == "" {
|
||||||
x.prefix = prefix
|
x.prefix = prefix
|
||||||
x.def = def
|
x.def = def
|
||||||
@ -235,8 +214,6 @@ func loadpkgdata(file string, pkg string, data string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
|
func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
|
||||||
var prefix string
|
|
||||||
|
|
||||||
// skip white space
|
// skip white space
|
||||||
p := *pp
|
p := *pp
|
||||||
|
|
||||||
@ -249,7 +226,7 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prefix: (var|type|func|const)
|
// prefix: (var|type|func|const)
|
||||||
prefix = p
|
prefix := p
|
||||||
|
|
||||||
if len(p) < 7 {
|
if len(p) < 7 {
|
||||||
return -1
|
return -1
|
||||||
@ -268,7 +245,7 @@ loop:
|
|||||||
p = p[1:]
|
p = p[1:]
|
||||||
}
|
}
|
||||||
p = p[1:]
|
p = p[1:]
|
||||||
name := p
|
line := p
|
||||||
for len(p) > 0 && p[0] != '\n' {
|
for len(p) > 0 && p[0] != '\n' {
|
||||||
p = p[1:]
|
p = p[1:]
|
||||||
}
|
}
|
||||||
@ -277,9 +254,16 @@ loop:
|
|||||||
nerrors++
|
nerrors++
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
name = name[:len(name)-len(p)]
|
line = line[:len(line)-len(p)]
|
||||||
|
line = strings.TrimSuffix(line, " // indirect")
|
||||||
|
path, err := strconv.Unquote(line)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s: confused in import path: %q\n", os.Args[0], file, line)
|
||||||
|
nerrors++
|
||||||
|
return -1
|
||||||
|
}
|
||||||
p = p[1:]
|
p = p[1:]
|
||||||
imported(pkg, name)
|
imported(pkg, path)
|
||||||
goto loop
|
goto loop
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
|
fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
|
||||||
@ -753,66 +737,60 @@ func addexport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Pkg struct {
|
type Pkg struct {
|
||||||
mark uint8
|
mark bool
|
||||||
checked uint8
|
checked bool
|
||||||
next *Pkg
|
path string
|
||||||
path_ string
|
|
||||||
impby []*Pkg
|
impby []*Pkg
|
||||||
all *Pkg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var phash [1024]*Pkg
|
var (
|
||||||
|
// pkgmap records the imported-by relationship between packages.
|
||||||
|
// Entries are keyed by package path (e.g., "runtime" or "net/url").
|
||||||
|
pkgmap = map[string]*Pkg{}
|
||||||
|
|
||||||
var pkgall *Pkg
|
pkgall []*Pkg
|
||||||
|
)
|
||||||
|
|
||||||
func getpkg(path_ string) *Pkg {
|
func lookupPkg(path string) *Pkg {
|
||||||
h := hashstr(path_) % len(phash)
|
if p, ok := pkgmap[path]; ok {
|
||||||
for p := phash[h]; p != nil; p = p.next {
|
return p
|
||||||
if p.path_ == path_ {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
p := new(Pkg)
|
p := &Pkg{path: path}
|
||||||
p.path_ = path_
|
pkgmap[path] = p
|
||||||
p.next = phash[h]
|
pkgall = append(pkgall, p)
|
||||||
phash[h] = p
|
|
||||||
p.all = pkgall
|
|
||||||
pkgall = p
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func imported(pkg string, import_ string) {
|
// imported records that package pkg imports package imp.
|
||||||
|
func imported(pkg, imp string) {
|
||||||
// everyone imports runtime, even runtime.
|
// everyone imports runtime, even runtime.
|
||||||
if import_ == "\"runtime\"" {
|
if imp == "runtime" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg = fmt.Sprintf("%q", pkg) // turn pkg path into quoted form, freed below
|
p := lookupPkg(pkg)
|
||||||
p := getpkg(pkg)
|
i := lookupPkg(imp)
|
||||||
i := getpkg(import_)
|
|
||||||
i.impby = append(i.impby, p)
|
i.impby = append(i.impby, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cycle(p *Pkg) *Pkg {
|
func (p *Pkg) cycle() *Pkg {
|
||||||
if p.checked != 0 {
|
if p.checked {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.mark != 0 {
|
if p.mark {
|
||||||
nerrors++
|
nerrors++
|
||||||
fmt.Printf("import cycle:\n")
|
fmt.Printf("import cycle:\n")
|
||||||
fmt.Printf("\t%s\n", p.path_)
|
fmt.Printf("\t%s\n", p.path)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
p.mark = 1
|
p.mark = true
|
||||||
var bad *Pkg
|
for _, q := range p.impby {
|
||||||
for i := 0; i < len(p.impby); i++ {
|
if bad := q.cycle(); bad != nil {
|
||||||
bad = cycle(p.impby[i])
|
p.mark = false
|
||||||
if bad != nil {
|
p.checked = true
|
||||||
p.mark = 0
|
fmt.Printf("\timports %s\n", p.path)
|
||||||
p.checked = 1
|
|
||||||
fmt.Printf("\timports %s\n", p.path_)
|
|
||||||
if bad == p {
|
if bad == p {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -820,14 +798,14 @@ func cycle(p *Pkg) *Pkg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.checked = 1
|
p.checked = true
|
||||||
p.mark = 0
|
p.mark = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importcycles() {
|
func importcycles() {
|
||||||
for p := pkgall; p != nil; p = p.all {
|
for _, p := range pkgall {
|
||||||
cycle(p)
|
p.cycle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user