Beispiel #1
0
func (g *Grapher) assignPaths(s *types.Scope, prefix []string, pkgscope bool) {
	g.scopePaths[s] = prefix

	for _, name := range s.Names() {
		e := s.Lookup(name)
		if _, seen := g.paths[e]; seen {
			continue
		}
		path := append(append([]string{}, prefix...), name)
		g.paths[e] = path
		g.exported[e] = ast.IsExported(name) && pkgscope
		g.pkgscope[e] = pkgscope

		if tn, ok := e.(*types.TypeName); ok {
			// methods
			named := tn.Type().(*types.Named)
			g.assignMethodPaths(named, path, pkgscope)

			// struct fields
			typ := derefType(tn.Type().Underlying())
			if styp, ok := typ.(*types.Struct); ok {
				g.assignStructFieldPaths(styp, path, pkgscope)
			}
		} else if v, ok := e.(*types.Var); ok {
			// struct fields if type is anonymous struct
			if styp, ok := derefType(v.Type()).(*types.Struct); ok {
				g.assignStructFieldPaths(styp, path, pkgscope)
			}
		}
	}

	seenChildPrefixes := map[string]struct{}{}
	for i := 0; i < s.NumChildren(); i++ {
		c := s.Child(i)
		childPrefix := prefix
		pkgscope := pkgscope

		if path := g.scopePath(prefix, c); path != nil {
			childPrefix = append([]string{}, path...)
			pkgscope = false
		}

		if len(childPrefix) >= 1 {
			// Ensure all child prefixes are unique. This is an issue when you
			// have, for example:
			//  func init() { x:=0;_=x};func init() { x:=0;_=x}
			// This is valid Go code but if we don't uniquify the two `x`s, they
			// will have the same paths.
			cp := strings.Join(childPrefix, "/")
			if _, seen := seenChildPrefixes[cp]; seen {
				childPrefix[len(childPrefix)-1] += fmt.Sprintf("$%d", i)
			}
			seenChildPrefixes[cp] = struct{}{}
		}

		g.assignPaths(c, childPrefix, pkgscope)
	}
}