goose: use marker functions instead of comments

To avoid making this CL too large, I did not migrate the existing goose
comments through the repository.  This will be addressed in a subsequent
CL.

Reviewed-by: Tuo Shan <shantuo@google.com>
This commit is contained in:
Ross Light
2018-04-27 13:44:54 -04:00
parent 13698e656a
commit f8e446fa17
59 changed files with 713 additions and 983 deletions

View File

@@ -8,7 +8,7 @@ import (
"go/ast"
"go/build"
"go/format"
"go/parser"
"go/token"
"go/types"
"sort"
"strconv"
@@ -22,8 +22,24 @@ import (
// Generate performs dependency injection for a single package,
// returning the gofmt'd Go source code.
func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
conf := newLoaderConfig(bctx, wd, true)
mainPkg, err := bctx.Import(pkg, wd, build.FindOnly)
if err != nil {
return nil, fmt.Errorf("load: %v", err)
}
// TODO(light): Stop errors from printing to stderr.
conf := &loader.Config{
Build: new(build.Context),
Cwd: wd,
TypeCheckFuncBodies: func(path string) bool {
return path == mainPkg.ImportPath
},
}
*conf.Build = *bctx
n := len(conf.Build.BuildTags)
// TODO(light): Only apply gooseinject build tag on main package.
conf.Build.BuildTags = append(conf.Build.BuildTags[:n:n], "gooseinject")
conf.Import(pkg)
prog, err := conf.Load()
if err != nil {
return nil, fmt.Errorf("load: %v", err)
@@ -34,47 +50,23 @@ func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
}
pkgInfo := prog.InitialPackages()[0]
g := newGen(prog, pkgInfo.Pkg.Path())
r := newImportResolver(conf, prog.Fset)
mc := newProviderSetCache(prog, r)
oc := newObjectCache(prog)
for _, f := range pkgInfo.Files {
if !isInjectFile(f) {
continue
}
fileScope := pkgInfo.Scopes[f]
groups := parseFile(prog.Fset, f)
for _, decl := range f.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok {
continue
}
var dg directiveGroup
for _, dg = range groups {
if dg.decl == decl {
break
}
useCall := isInjector(&pkgInfo.Info, fn)
if useCall == nil {
continue
}
if dg.decl != decl {
dg = directiveGroup{}
}
var sets []symref
for _, d := range dg.dirs {
if d.kind != "use" {
return nil, fmt.Errorf("%v: cannot use %s directive on inject function", prog.Fset.Position(d.pos), d.kind)
}
args := d.args()
if len(args) == 0 {
return nil, fmt.Errorf("%v: goose:use must have at least one provider set reference", prog.Fset.Position(d.pos))
}
for _, arg := range args {
ref, err := parseSymbolRef(r, arg, fileScope, g.currPackage, d.pos)
if err != nil {
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(d.pos), err)
}
sets = append(sets, ref)
}
set, err := oc.processNewSet(pkgInfo, useCall)
if err != nil {
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(fn.Pos()), err)
}
sig := pkgInfo.ObjectOf(fn.Name).Type().(*types.Signature)
if err := g.inject(mc, fn.Name.Name, sig, sets); err != nil {
if err := g.inject(prog.Fset, fn.Name.Name, sig, set); err != nil {
return nil, fmt.Errorf("%v: %v", prog.Fset.Position(fn.Pos()), err)
}
}
@@ -89,23 +81,6 @@ func Generate(bctx *build.Context, wd string, pkg string) ([]byte, error) {
return fmtSrc, nil
}
func newLoaderConfig(bctx *build.Context, wd string, inject bool) *loader.Config {
// TODO(light): Stop errors from printing to stderr.
conf := &loader.Config{
Build: bctx,
ParserMode: parser.ParseComments,
Cwd: wd,
TypeCheckFuncBodies: func(string) bool { return false },
}
if inject {
conf.Build = new(build.Context)
*conf.Build = *bctx
n := len(conf.Build.BuildTags)
conf.Build.BuildTags = append(conf.Build.BuildTags[:n:n], "gooseinject")
}
return conf
}
// gen is the generator state.
type gen struct {
currPackage string
@@ -150,7 +125,7 @@ func (g *gen) frame() []byte {
}
// inject emits the code for an injector.
func (g *gen) inject(mc *providerSetCache, name string, sig *types.Signature, sets []symref) error {
func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set *ProviderSet) error {
results := sig.Results()
var returnsCleanup, returnsErr bool
switch results.Len() {
@@ -184,7 +159,7 @@ func (g *gen) inject(mc *providerSetCache, name string, sig *types.Signature, se
for i := 0; i < params.Len(); i++ {
given[i] = params.At(i).Type()
}
calls, err := solve(mc, outType, given, sets)
calls, err := solve(fset, outType, given, set)
if err != nil {
return err
}