Exemple #1
0
func makePkg(t *testing.T, src string) (*Package, error) {
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
	if err != nil {
		return nil, err
	}
	// use the package name as package path
	conf := Config{Importer: importer.Default([]*ast.File{file})}
	return conf.Check(file.Name.Name, fset, []*ast.File{file}, nil)
}
Exemple #2
0
func pkgFor(path, source string, info *Info) (*Package, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, source, 0)
	if err != nil {
		return nil, err
	}

	conf := Config{Importer: importer.Default([]*ast.File{f}), AllowUseUninitializedVars: true, AllowUninitializedExprs: true}
	return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
}
Exemple #3
0
func checkFiles(t *testing.T, testfiles []string) {
	// parse files and collect parser errors
	files, errlist := parseFiles(t, testfiles)

	pkgName := "<no package>"
	if len(files) > 0 {
		pkgName = files[0].Name.Name
	}

	if *listErrors && len(errlist) > 0 {
		t.Errorf("--- %s:", pkgName)
		for _, err := range errlist {
			t.Error(err)
		}
	}

	// typecheck and collect typechecker errors
	conf := Config{AllowUseUninitializedVars: true, AllowUninitializedExprs: true}
	// special case for importC.src
	if len(testfiles) == 1 && testfiles[0] == "testdata/importC.src" {
		conf.FakeImportC = true
	}
	conf.Importer = importer.Default(files)
	conf.Error = func(err error) {
		if *listErrors {
			t.Error(err)
			return
		}
		// Ignore secondary error messages starting with "\t";
		// they are clarifying messages for a primary error.
		if !strings.Contains(err.Error(), ": \t") {
			errlist = append(errlist, err)
		}
	}
	conf.Check(pkgName, fset, files, nil)

	if *listErrors {
		return
	}

	// match and eliminate errors;
	// we are expecting the following errors
	errmap := errMap(t, pkgName, files)
	eliminate(t, errmap, errlist)

	// there should be no expected errors left
	if len(errmap) > 0 {
		t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap))
		for pos, list := range errmap {
			for _, rx := range list {
				t.Errorf("%s: %q", pos, rx)
			}
		}
	}
}
Exemple #4
0
func TestIssue5770(t *testing.T) {
	src := `package p; type S struct{T}`
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		t.Fatal(err)
	}

	conf := Config{Importer: importer.Default([]*ast.File{f})}
	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
	want := "undeclared name: T"
	if err == nil || !strings.Contains(err.Error(), want) {
		t.Errorf("got: %v; want: %s", err, want)
	}
}
Exemple #5
0
// ExampleMethodSet prints the method sets of various types.
func ExampleMethodSet() {
	// Parse a single source file.
	const input = `
package temperature
import "fmt"
type Celsius float64
func (c Celsius) String() string  { return fmt.Sprintf("%g°C", c) }
func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
`
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "celsius.go", input, 0)
	if err != nil {
		log.Fatal(err)
	}

	// Type-check a package consisting of this file.
	// Type information for the imported packages
	// comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
	conf := types.Config{Importer: importer.Default([]*ast.File{f})}
	pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	// Print the method sets of Celsius and *Celsius.
	celsius := pkg.Scope().Lookup("Celsius").Type()
	for _, t := range []types.Type{celsius, types.NewPointer(celsius)} {
		fmt.Printf("Method set of %s:\n", t)
		mset := types.NewMethodSet(t)
		for i := 0; i < mset.Len(); i++ {
			fmt.Println(mset.At(i))
		}
		fmt.Println()
	}

	// Output:
	// Method set of temperature.Celsius:
	// method (temperature.Celsius) String() string
	//
	// Method set of *temperature.Celsius:
	// method (*temperature.Celsius) SetF(f float64)
	// method (*temperature.Celsius) String() string
}
Exemple #6
0
func TestHilbert(t *testing.T) {
	// generate source
	src := program(*H, *out)
	if *out != "" {
		ioutil.WriteFile(*out, src, 0666)
		return
	}

	// parse source
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "hilbert.go", src, 0)
	if err != nil {
		t.Fatal(err)
	}

	// type-check file
	DefPredeclaredTestFuncs() // define assert built-in
	conf := Config{Importer: importer.Default([]*ast.File{f})}
	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
	if err != nil {
		t.Fatal(err)
	}
}
Exemple #7
0
func testBuiltinSignature(t *testing.T, name, src0, want string) {
	src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		t.Errorf("%s: %s", src0, err)
		return
	}

	conf := Config{Importer: importer.Default([]*ast.File{f}), AllowUseUninitializedVars: true}
	uses := make(map[*ast.Ident]Object)
	types := make(map[ast.Expr]TypeAndValue)
	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
	if err != nil {
		t.Errorf("%s: %s", src0, err)
		return
	}

	// find called function
	n := 0
	var fun ast.Expr
	for x := range types {
		if call, _ := x.(*ast.CallExpr); call != nil {
			fun = call.Fun
			n++
		}
	}
	if n != 1 {
		t.Errorf("%s: got %d CallExprs; want 1", src0, n)
		return
	}

	// check recorded types for fun and descendents (may be parenthesized)
	for {
		// the recorded type for the built-in must match the wanted signature
		typ := types[fun].Type
		if typ == nil {
			t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
			return
		}
		if got := typ.String(); got != want {
			t.Errorf("%s: got type %s; want %s", src0, got, want)
			return
		}

		// called function must be a (possibly parenthesized, qualified)
		// identifier denoting the expected built-in
		switch p := fun.(type) {
		case *ast.Ident:
			obj := uses[p]
			if obj == nil {
				t.Errorf("%s: no object found for %s", src0, p)
				return
			}
			bin, _ := obj.(*Builtin)
			if bin == nil {
				t.Errorf("%s: %s does not denote a built-in", src0, p)
				return
			}
			if bin.Name() != name {
				t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
				return
			}
			return // we're done

		case *ast.ParenExpr:
			fun = p.X // unpack

		case *ast.SelectorExpr:
			// built-in from package unsafe - ignore details
			return // we're done

		default:
			t.Errorf("%s: invalid function call", src0)
			return
		}
	}
}
Exemple #8
0
func TestEvalPos(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	// The contents of /*-style comments are of the form
	//	expr => value, type
	// where value may be the empty string.
	// Each expr is evaluated at the position of the comment
	// and the result is compared with the expected value
	// and type.
	var sources = []string{
		`
		package p
		import "fmt"
		import m "math"
		const c = 3.0
		type T []int
		func f(a int, s string) float64 {
			fmt.Println("calling f")
			_ = m.Pi // use package math
			const d int = c + 1
			var x int
			x = a + len(s)
			return float64(x)
			/* true => true, untyped bool */
			/* fmt.Println => , func(a ...interface{}) (n int, err ?error) */
			/* c => 3, untyped float */
			/* T => , p.T */
			/* a => , int */
			/* s => , string */
			/* d => 4, int */
			/* x => , int */
			/* d/c => 1, int */
			/* c/2 => 3/2, untyped float */
			/* m.Pi < m.E => false, untyped bool */
		}
		`,
		`
		package p
		/* c => 3, untyped float */
		type T1 /* T1 => , p.T1 */ struct {}
		var v1 /* v1 => , int */ = 42
		func /* f1 => , func(v1 float64) */ f1(v1 float64) {
			/* f1 => , func(v1 float64) */
			/* v1 => , float64 */
			var c /* c => 3, untyped float */ = "foo" /* c => , string */
			{
				var c struct {
					c /* c => , string */ int
				}
				/* c => , struct{c int} */
				_ = c
			}
			_ = func(a, b, c int) /* c => , string */ {
				/* c => , int */
			}
			_ = c
			type FT /* FT => , p.FT */ interface{}
		}
		`,
		`
		package p
		/* T => , p.T */
		`,
	}

	fset := token.NewFileSet()
	var files []*ast.File
	for i, src := range sources {
		file, err := parser.ParseFile(fset, "p", src, parser.ParseComments)
		if err != nil {
			t.Fatalf("could not parse file %d: %s", i, err)
		}
		files = append(files, file)
	}

	conf := Config{Importer: importer.Default(files)}
	pkg, err := conf.Check("p", fset, files, nil)
	if err != nil {
		t.Fatal(err)
	}

	for _, file := range files {
		for _, group := range file.Comments {
			for _, comment := range group.List {
				s := comment.Text
				if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" {
					str, typ := split(s[2:len(s)-2], ", ")
					str, val := split(str, "=>")
					testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val)
				}
			}
		}
	}
}
Exemple #9
0
// This tests that the package associated with the types.Object.Pkg method
// is the type's package independent of the order in which the imports are
// listed in the sources src1, src2 below.
// The actual issue is in go/internal/gcimporter which has a corresponding
// test; we leave this test here to verify correct behavior at the go/types
// level.
func TestIssue13898(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	const src0 = `
package main

import "github.com/tcard/sgo/sgo/types"

func main() {
	var info types.Info
	for _, obj := range info.Uses {
		_ = obj.Pkg()
	}
}
`
	// like src0, but also imports go/importer
	const src1 = `
package main

import (
	"github.com/tcard/sgo/sgo/types"
	_ "github.com/tcard/sgo/sgo/importer"
)

func main() {
	var info types.Info
	for _, obj := range info.Uses {
		_ = obj.Pkg()
	}
}
`
	// like src1 but with different import order
	// (used to fail with this issue)
	const src2 = `
package main

import (
	_ "github.com/tcard/sgo/sgo/importer"
	"github.com/tcard/sgo/sgo/types"
)

func main() {
	var info types.Info
	for _, obj := range info.Uses {
		_ = obj.Pkg()
	}
}
`
	f := func(test, src string) {
		f, err := parser.ParseFile(fset, "", src, 0)
		if err != nil {
			t.Fatal(err)
		}
		cfg := Config{Importer: importer.Default([]*ast.File{f})}
		info := Info{Uses: make(map[*ast.Ident]Object)}
		_, err = cfg.Check("main", fset, []*ast.File{f}, &info)
		if err != nil {
			t.Fatal(err)
		}

		var pkg *Package
		count := 0
		for id, obj := range info.Uses {
			if id.Name == "Pkg" {
				pkg = obj.Pkg()
				count++
			}
		}
		if count != 1 {
			t.Fatalf("%s: got %d entries named Pkg; want 1", test, count)
		}
		if pkg.Name() != "types" {
			t.Fatalf("%s: got %v; want package types", test, pkg)
		}
	}

	f("src0", src0)
	f("src1", src1)
	f("src2", src2)
}
Exemple #10
0
// ExampleScope prints the tree of Scopes of a package created from a
// set of parsed files.
func ExampleScope() {
	// Parse the source files for a package.
	fset := token.NewFileSet()
	var files []*ast.File
	for _, file := range []struct{ name, input string }{
		{"main.go", `
package main
import "fmt"
func main() {
	freezing := FToC(-18)
	fmt.Println(freezing, Boiling) }
`},
		{"celsius.go", `
package main
import "fmt"
type Celsius float64
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
const Boiling Celsius = 100
`},
	} {
		f, err := parser.ParseFile(fset, file.name, file.input, 0)
		if err != nil {
			log.Fatal(err)
		}
		files = append(files, f)
	}

	// Type-check a package consisting of these files.
	// Type information for the imported "fmt" package
	// comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
	conf := types.Config{Importer: importer.Default(files)}
	pkg, err := conf.Check("temperature", fset, files, nil)
	if err != nil {
		log.Fatal(err)
	}

	// Print the tree of scopes.
	// For determinism, we redact addresses.
	var buf bytes.Buffer
	pkg.Scope().WriteTo(&buf, 0, true)
	rx := regexp.MustCompile(` 0x[a-fA-F0-9]*`)
	fmt.Println(rx.ReplaceAllString(buf.String(), ""))

	// Output:
	// package "temperature" scope {
	// .  const temperature.Boiling temperature.Celsius
	// .  type temperature.Celsius float64
	// .  func temperature.FToC(f float64) temperature.Celsius
	// .  func temperature.main()
	//
	// .  main.go scope {
	// .  .  package fmt
	//
	// .  .  function scope {
	// .  .  .  var freezing temperature.Celsius
	// .  .  }.  }
	// .  celsius.go scope {
	// .  .  package fmt
	//
	// .  .  function scope {
	// .  .  .  var c temperature.Celsius
	// .  .  }
	// .  .  function scope {
	// .  .  .  var f float64
	// .  .  }.  }}
}