Beispiel #1
0
func (p *Parser) Parse(path string, cursor SourceLocation, unsaved []UnsavedDocument, options Options) (*Parsed, error) {
	if len(options.GoPath) == 0 {
		options.GoPath = os.Getenv("GOPATH")
	}

	path, uns := p.canonicalPaths(path, unsaved)

	var info types.Info

	info.Types = make(map[ast.Expr]types.Type)
	info.Objects = make(map[*ast.Ident]types.Object)

	fs := token.NewFileSet()

	started := time.Now()

	dname := filepath.Dir(path)
	f, astf, tpkg, err := p.importSourcePackage(fs, path, dname, uns, options, &info)

	errors, _ := err.(scanner.ErrorList)

	return &Parsed{
		Info:     &info,
		Package:  tpkg,
		FileSet:  fs,
		Ast:      astf,
		File:     f,
		Errors:   errors,
		Duration: time.Now().Sub(started),
	}, nil
}
Beispiel #2
0
// errorOrVoid filters the list of functions to only those that return only an
// error or have no return value.
func errorOrVoid(fns []*ast.FuncDecl, info types.Info) []*ast.FuncDecl {
	fds := []*ast.FuncDecl{}

	for _, fn := range fns {
		// look for functions with 0 or 1 return values
		res := fn.Type.Results
		if res.NumFields() > 1 {
			continue
		}
		// 0 return value is ok
		if res.NumFields() == 0 {
			fds = append(fds, fn)
			continue
		}
		// if 1 return value, look for those that return an error
		ret := res.List[0]

		// handle (a, b, c int)
		if len(ret.Names) > 1 {
			continue
		}
		t := info.TypeOf(ret.Type)
		if t != nil && t.String() == "error" {
			fds = append(fds, fn)
		}
	}
	return fds
}
Beispiel #3
0
func functions(f *ast.File, info types.Info, fset *token.FileSet) ([]Function, error) {
	fns := exportedFuncs(f, fset)
	fns = errorOrVoid(fns, info)

	cmtMap := ast.NewCommentMap(fset, f, f.Comments)

	functions := make([]Function, len(fns))

	for i, fn := range fns {
		fun := Function{Name: fn.Name.Name}
		fun.Comment = combine(cmtMap[fn])

		// we only support null returns or error returns, so if there's a
		// return, it's an error.
		if len(fn.Type.Results.List) > 0 {
			fun.IsError = true
		}
		params := fn.Type.Params.List
		fun.Params = make([]Param, 0, len(params))
		for _, field := range params {
			t := info.TypeOf(field.Type)
			pointer := false
			if p, ok := t.(*types.Pointer); ok {
				t = p.Elem()
				pointer = true
			}
			if b, ok := t.(*types.Basic); ok {
				if b.Kind() == types.UnsafePointer {
					log.Printf(
						"Can't create command for function %q because its parameter %q is an unsafe.Pointer.",
						fn.Name.Name,
						field.Names[0])
					break
				}

				fieldCmt := combine(cmtMap[field])
				// handle a, b, c int
				for _, name := range field.Names {
					nameCmt := combine(cmtMap[name])
					if nameCmt == "" {
						nameCmt = fieldCmt
					}
					param := Param{
						Name:      name.Name,
						Type:      b.Kind(),
						IsPointer: pointer,
						Comment:   nameCmt,
					}
					fun.Params = append(fun.Params, param)
				}
				continue
			}
		}
		functions[i] = fun
	}
	return functions, nil
}
Beispiel #4
0
func (c *compiler) typecheck(pkgpath string, fset *token.FileSet, files []*ast.File) (*types.Package, error) {
	config := &types.Config{
		Sizeof:    c.llvmtypes.Sizeof,
		Alignof:   c.llvmtypes.Alignof,
		Offsetsof: c.llvmtypes.Offsetsof,
	}

	var info types.Info
	objectdata := make(map[types.Object]*ObjectData)
	info.Values = c.typeinfo.Values
	info.Types = c.typeinfo.Types
	info.Implicits = make(map[ast.Node]types.Object)
	info.Objects = make(map[*ast.Ident]types.Object)
	pkg, err := config.Check(pkgpath, fset, files, &info)
	if err != nil {
		return nil, err
	}

	for id, obj := range info.Objects {
		if obj == nil {
			continue
		}
		c.typeinfo.Objects[id] = obj
		objectdata[obj] = &ObjectData{Ident: id, Package: pkg}
	}

	for node, obj := range info.Implicits {
		id := ast.NewIdent(obj.Name())
		c.typeinfo.Objects[id] = obj
		c.typeinfo.Implicits[node] = obj
		objectdata[obj] = &ObjectData{Ident: id, Package: pkg}
	}

	for _, pkg := range pkg.Imports() {
		assocObjectPackages(pkg, objectdata)
	}

	for object, data := range objectdata {
		if object, ok := object.(*types.TypeName); ok {
			// Add TypeNames to the LLVMTypeMap's TypeStringer.
			c.llvmtypes.pkgmap[object] = data.Package

			// Record exported types for generating runtime type information.
			// c.pkg is nil iff the package being checked is the package
			// being compiled.
			if c.pkg == nil && object.Pkg() == pkg && ast.IsExported(object.Name()) {
				c.exportedtypes = append(c.exportedtypes, object.Type())
			}
		}
		c.objectdata[object] = data
	}

	return pkg, nil
}
Beispiel #5
0
func (c *compiler) typecheck(pkgpath string, fset *token.FileSet, files []*ast.File) (*types.Package, error) {
	var errors string
	var imp = importer{compiler: c}
	config := &types.Config{
		Error: func(err error) {
			if errors != "" {
				errors += "\n"
			}
			errors += err.Error()
		},
		Import: imp.Import,
		Sizes:  c.llvmtypes,
	}

	var info types.Info
	objectdata := make(map[types.Object]*ObjectData)
	info.Values = c.typeinfo.Values
	info.Types = c.typeinfo.Types
	info.Selections = c.typeinfo.Selections
	info.Implicits = make(map[ast.Node]types.Object)
	info.Objects = make(map[*ast.Ident]types.Object)
	pkg, err := config.Check(pkgpath, fset, files, &info)
	if err != nil {
		return nil, fmt.Errorf("%s", errors)
	}

	for id, obj := range info.Objects {
		if obj == nil {
			continue
		}
		c.typeinfo.Objects[id] = obj
		data := objectdata[obj]
		if data == nil {
			objectdata[obj] = &ObjectData{Ident: id}
		} else if data.Ident.Obj == nil {
			data.Ident = id
		}
	}

	for node, obj := range info.Implicits {
		id := ast.NewIdent(obj.Name())
		c.typeinfo.Objects[id] = obj
		c.typeinfo.Implicits[node] = obj
		objectdata[obj] = &ObjectData{Ident: id}
	}

	for object, data := range objectdata {
		if object, ok := object.(*types.TypeName); ok {
			// Record exported types for generating runtime type information.
			// c.pkg is nil iff the package being checked is the package
			// being compiled.
			if c.pkg == nil && object.Pkg() == pkg && ast.IsExported(object.Name()) {
				c.exportedtypes = append(c.exportedtypes, object.Type())
			}
		}
		c.objectdata[object] = data
	}

	return pkg, nil
}