Exemple #1
0
// pkgString returns a string representation of a package's exported interface.
func pkgString(pkg *types.Package) string {
	var buf bytes.Buffer

	fmt.Fprintf(&buf, "package %s\n", pkg.Name())

	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			obj := scope.Lookup(name)
			buf.WriteString(obj.String())

			switch obj := obj.(type) {
			case *types.Const:
				// For now only print constant values if they are not float
				// or complex. This permits comparing go/types results with
				// gc-generated gcimported package interfaces.
				info := obj.Type().Underlying().(*types.Basic).Info()
				if info&types.IsFloat == 0 && info&types.IsComplex == 0 {
					fmt.Fprintf(&buf, " = %s", obj.Val())
				}

			case *types.TypeName:
				// Print associated methods.
				// Basic types (e.g., unsafe.Pointer) have *types.Basic
				// type rather than *types.Named; so we need to check.
				if typ, _ := obj.Type().(*types.Named); typ != nil {
					if n := typ.NumMethods(); n > 0 {
						// Sort methods by name so that we get the
						// same order independent of whether the
						// methods got imported or coming directly
						// for the source.
						// TODO(gri) This should probably be done
						// in go/types.
						list := make([]*types.Func, n)
						for i := 0; i < n; i++ {
							list[i] = typ.Method(i)
						}
						sort.Sort(byName(list))

						buf.WriteString("\nmethods (\n")
						for _, m := range list {
							fmt.Fprintf(&buf, "\t%s\n", m)
						}
						buf.WriteString(")")
					}
				}
			}
			buf.WriteByte('\n')
		}
	}

	return buf.String()
}
Exemple #2
0
// NewPackageDef creates a new Def that represents a Go package.
func (g *Grapher) NewPackageDef(pkgInfo *loader.PackageInfo, pkg *types.Package) (*Def, error) {
	var pkgDir string
	if len(pkgInfo.Files) > 0 {
		pkgDir = filepath.Dir(g.program.Fset.Position(pkgInfo.Files[0].Package).Filename)
	}

	return &Def{
		Name: pkg.Name(),

		DefKey: &DefKey{PackageImportPath: pkg.Path(), Path: []string{}},

		File: pkgDir,

		DefInfo: definfo.DefInfo{
			Exported: true,
			PkgName:  pkg.Name(),
			Kind:     definfo.Package,
		},
	}, nil
}
Exemple #3
0
func defaultFileName(lang string, pkg *types.Package) string {
	if *outdir == "" {
		return ""
	}

	switch lang {
	case "java":
		firstRune, size := utf8.DecodeRuneInString(pkg.Name())
		className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
		return filepath.Join(*outdir, className+".java")
	case "go":
		return filepath.Join(*outdir, "go_"+pkg.Name()+".go")
	case "objc":
		firstRune, size := utf8.DecodeRuneInString(pkg.Name())
		className := string(unicode.ToUpper(firstRune)) + pkg.Name()[size:]
		return filepath.Join(*outdir, "Go"+className+".m")
	}
	errorf("unknown target language: %q", lang)
	os.Exit(exitStatus)
	return ""
}
Exemple #4
0
func (p *exporter) pkg(pkg *types.Package) {
	if trace {
		p.tracef("package { ")
		defer p.tracef("} ")
	}

	if pkg == nil {
		panic("unexpected nil pkg")
	}

	// if the package was seen before, write its index (>= 0)
	if i, ok := p.pkgIndex[pkg]; ok {
		p.int(i)
		return
	}
	p.pkgIndex[pkg] = len(p.pkgIndex)

	// otherwise, write the package tag (< 0) and package data
	p.int(packageTag)
	p.string(pkg.Name())
	p.string(pkg.Path())
}
Exemple #5
0
// ExportData serializes the interface (exported package objects)
// of package pkg and returns the corresponding data. The export
// format is described elsewhere (TODO).
func ExportData(pkg *types.Package) []byte {
	p := exporter{
		data:     append([]byte(magic), format()),
		pkgIndex: make(map[*types.Package]int),
		typIndex: make(map[types.Type]int),
	}

	// populate typIndex with predeclared types
	for _, t := range predeclared {
		p.typIndex[t] = len(p.typIndex)
	}

	if trace {
		p.tracef("export %s\n", pkg.Name())
		defer p.tracef("\n")
	}

	p.string(version)

	p.pkg(pkg)

	// collect exported objects from package scope
	var list []types.Object
	scope := pkg.Scope()
	for _, name := range scope.Names() {
		if exported(name) {
			list = append(list, scope.Lookup(name))
		}
	}

	// write objects
	p.int(len(list))
	for _, obj := range list {
		p.obj(obj)
	}

	return p.data
}
Exemple #6
0
func testExportImport(t *testing.T, pkg0 *types.Package, path string) (size, gcsize int) {
	data := ExportData(pkg0)
	size = len(data)

	imports := make(map[string]*types.Package)
	n, pkg1, err := ImportData(imports, data)
	if err != nil {
		t.Errorf("package %s: import failed: %s", pkg0.Name(), err)
		return
	}
	if n != size {
		t.Errorf("package %s: not all input data consumed", pkg0.Name())
		return
	}

	s0 := pkgString(pkg0)
	s1 := pkgString(pkg1)
	if s1 != s0 {
		t.Errorf("package %s: \nimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s1, s0)
	}

	// If we have a standard library, compare also against the gcimported package.
	if path == "" {
		return // not std library
	}

	gcdata, err := gcExportData(path)
	if err != nil {
		if pkg0.Name() == "main" {
			return // no export data present for main package
		}
		t.Errorf("package %s: couldn't get export data: %s", pkg0.Name(), err)
	}
	gcsize = len(gcdata)

	imports = make(map[string]*types.Package)
	pkg2, err := gcImportData(imports, gcdata, path)
	if err != nil {
		t.Errorf("package %s: gcimport failed: %s", pkg0.Name(), err)
		return
	}

	s2 := pkgString(pkg2)
	if s2 != s0 {
		t.Errorf("package %s: \ngcimport got:\n%s\nwant:\n%s\n", pkg0.Name(), s2, s0)
	}

	return
}
Exemple #7
0
func (sym *symtab) addType(obj types.Object, t types.Type) {
	fn := sym.typename(t, nil)
	n := sym.typename(t, sym.pkg)
	var pkg *types.Package
	if obj != nil {
		pkg = obj.Pkg()
	}
	id := n
	if pkg != nil {
		id = pkg.Name() + "_" + n
	}
	kind := skType
	switch typ := t.(type) {
	case *types.Basic:
		kind |= skBasic
		styp := sym.symtype(typ)
		if styp == nil {
			panic(fmt.Errorf("builtin type not already known [%s]!", n))
		}

	case *types.Array:
		sym.addArrayType(pkg, obj, t, kind, id, n)

	case *types.Slice:
		sym.addSliceType(pkg, obj, t, kind, id, n)

	case *types.Signature:
		sym.addSignatureType(pkg, obj, t, kind, id, n)

	case *types.Named:
		kind |= skNamed
		switch typ := typ.Underlying().(type) {
		case *types.Struct:
			sym.addStructType(pkg, obj, t, kind, id, n)

		case *types.Basic:
			bsym := sym.symtype(typ)
			sym.syms[fn] = &symbol{
				gopkg:   pkg,
				goobj:   obj,
				gotyp:   t,
				kind:    kind | skBasic,
				id:      id,
				goname:  n,
				cgoname: "cgo_type_" + id,
				cpyname: "cpy_type_" + id,
				pyfmt:   bsym.pyfmt,
				pybuf:   bsym.pybuf,
				pysig:   "object",
				c2py:    "cgopy_cnv_c2py_" + id,
				py2c:    "cgopy_cnv_py2c_" + id,
				pychk:   fmt.Sprintf("cpy_func_%[1]s_check(%%s)", id),
			}

		case *types.Array:
			sym.addArrayType(pkg, obj, t, kind, id, n)

		case *types.Slice:
			sym.addSliceType(pkg, obj, t, kind, id, n)

		case *types.Signature:
			sym.addSignatureType(pkg, obj, t, kind, id, n)

		case *types.Pointer:
			sym.addPointerType(pkg, obj, t, kind, id, n)

		case *types.Interface:
			sym.addInterfaceType(pkg, obj, t, kind, id, n)

		default:
			panic(fmt.Errorf("unhandled named-type: [%T]\n%#v\n", obj, t))
		}

		// add methods
		for i := 0; i < typ.NumMethods(); i++ {
			m := typ.Method(i)
			if !m.Exported() {
				continue
			}
			if true {
				mid := id + "_" + m.Name()
				mname := m.Name()
				sym.addMethod(pkg, m, m.Type(), skFunc, mid, mname)
			}
		}

	case *types.Pointer:
		sym.addPointerType(pkg, obj, t, kind, id, n)

	case *types.Map:
		sym.addMapType(pkg, obj, t, kind, id, n)

	default:
		panic(fmt.Errorf("unhandled obj [%T]\ntype [%#v]", obj, t))
	}
}
Exemple #8
0
func (o *Object) setPkg(p *types.Package) {
	if p != nil {
		o.PkgPath = p.Path()
		o.PkgName = p.Name()
	}
}
Exemple #9
0
func (p *Processor) ProcessTypesPkg(typesPkg *types.Package) (*Package, error) {
	pkg := &Package{Name: typesPkg.Name()}
	p.processPackage(pkg, typesPkg)

	return pkg, nil
}
Exemple #10
0
func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
	// collect objects by kind
	var (
		consts   []*types.Const
		typem    []*types.Named    // non-interface types with methods
		typez    []*types.TypeName // interfaces or types without methods
		vars     []*types.Var
		funcs    []*types.Func
		builtins []*types.Builtin
		methods  = make(map[*types.Named][]*types.Selection) // method sets for named types
	)
	scope := pkg.Scope()
	for _, name := range scope.Names() {
		obj := scope.Lookup(name)
		if obj.Exported() {
			// collect top-level exported and possibly filtered objects
			if filter == nil || filter(obj) {
				switch obj := obj.(type) {
				case *types.Const:
					consts = append(consts, obj)
				case *types.TypeName:
					// group into types with methods and types without
					if named, m := methodsFor(obj); named != nil {
						typem = append(typem, named)
						methods[named] = m
					} else {
						typez = append(typez, obj)
					}
				case *types.Var:
					vars = append(vars, obj)
				case *types.Func:
					funcs = append(funcs, obj)
				case *types.Builtin:
					// for unsafe.Sizeof, etc.
					builtins = append(builtins, obj)
				}
			}
		} else if filter == nil {
			// no filtering: collect top-level unexported types with methods
			if obj, _ := obj.(*types.TypeName); obj != nil {
				// see case *types.TypeName above
				if named, m := methodsFor(obj); named != nil {
					typem = append(typem, named)
					methods[named] = m
				}
			}
		}
	}

	p.printf("package %s  // %q\n", pkg.Name(), pkg.Path())

	p.printDecl("const", len(consts), func() {
		for _, obj := range consts {
			p.printObj(obj)
			p.print("\n")
		}
	})

	p.printDecl("var", len(vars), func() {
		for _, obj := range vars {
			p.printObj(obj)
			p.print("\n")
		}
	})

	p.printDecl("type", len(typez), func() {
		for _, obj := range typez {
			p.printf("%s ", obj.Name())
			p.writeType(p.pkg, obj.Type().Underlying())
			p.print("\n")
		}
	})

	// non-interface types with methods
	for _, named := range typem {
		first := true
		if obj := named.Obj(); obj.Exported() {
			if first {
				p.print("\n")
				first = false
			}
			p.printf("type %s ", obj.Name())
			p.writeType(p.pkg, named.Underlying())
			p.print("\n")
		}
		for _, m := range methods[named] {
			if obj := m.Obj(); obj.Exported() {
				if first {
					p.print("\n")
					first = false
				}
				p.printFunc(m.Recv(), obj.(*types.Func))
				p.print("\n")
			}
		}
	}

	if len(funcs) > 0 {
		p.print("\n")
		for _, obj := range funcs {
			p.printFunc(nil, obj)
			p.print("\n")
		}
	}

	// TODO(gri) better handling of builtins (package unsafe only)
	if len(builtins) > 0 {
		p.print("\n")
		for _, obj := range builtins {
			p.printf("func %s() // builtin\n", obj.Name())
		}
	}

	p.print("\n")
}