add FieldsOf to inject fields of a struct directly (#138)
This commit is contained in:
@@ -32,6 +32,7 @@ const (
|
|||||||
funcProviderCall callKind = iota
|
funcProviderCall callKind = iota
|
||||||
structProvider
|
structProvider
|
||||||
valueExpr
|
valueExpr
|
||||||
|
selectorExpr
|
||||||
)
|
)
|
||||||
|
|
||||||
// A call represents a step of an injector function. It may be either a
|
// A call represents a step of an injector function. It may be either a
|
||||||
@@ -44,17 +45,21 @@ type call struct {
|
|||||||
// out is the type this step produces.
|
// out is the type this step produces.
|
||||||
out types.Type
|
out types.Type
|
||||||
|
|
||||||
// pkg and name identify the provider to call for kind ==
|
// pkg and name identify one of the following:
|
||||||
// funcProviderCall or the type to construct for kind ==
|
// 1) the provider to call for kind == funcProviderCall;
|
||||||
// structProvider.
|
// 2) the type to construct for kind == structProvider;
|
||||||
|
// 3) the name to select for kind == selectorExpr.
|
||||||
pkg *types.Package
|
pkg *types.Package
|
||||||
name string
|
name string
|
||||||
|
|
||||||
// args is a list of arguments to call the provider with. Each element is:
|
// args is a list of arguments to call the provider with. Each element is:
|
||||||
// a) one of the givens (args[i] < len(given)), or
|
// a) one of the givens (args[i] < len(given)),
|
||||||
// b) the result of a previous provider call (args[i] >= len(given))
|
// b) the result of a previous provider call (args[i] >= len(given))
|
||||||
//
|
//
|
||||||
// This will be nil for kind == valueExpr.
|
// This will be nil for kind == valueExpr.
|
||||||
|
//
|
||||||
|
// If kind == selectorExpr, then the length of this slice will be 1 and the
|
||||||
|
// "argument" will be the value to access fields from.
|
||||||
args []int
|
args []int
|
||||||
|
|
||||||
// varargs is true if the provider function is variadic.
|
// varargs is true if the provider function is variadic.
|
||||||
@@ -207,6 +212,29 @@ dfs:
|
|||||||
valueExpr: v.expr,
|
valueExpr: v.expr,
|
||||||
valueTypeInfo: v.info,
|
valueTypeInfo: v.info,
|
||||||
})
|
})
|
||||||
|
case pv.IsField():
|
||||||
|
f := pv.Field()
|
||||||
|
if index.At(f.Parent) == nil {
|
||||||
|
// Fields have one dependency which is the parent struct. Make
|
||||||
|
// sure to visit it first if it is not already visited.
|
||||||
|
stk = append(stk, curr, frame{t: f.Parent, from: curr.t, up: &curr})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
index.Set(curr.t, given.Len()+len(calls))
|
||||||
|
v := index.At(f.Parent)
|
||||||
|
if v == errAbort {
|
||||||
|
index.Set(curr.t, errAbort)
|
||||||
|
continue dfs
|
||||||
|
}
|
||||||
|
// Use the args[0] to store the position of the parent struct.
|
||||||
|
args := []int{v.(int)}
|
||||||
|
calls = append(calls, call{
|
||||||
|
kind: selectorExpr,
|
||||||
|
pkg: f.Pkg,
|
||||||
|
name: f.Name,
|
||||||
|
out: curr.t,
|
||||||
|
args: args,
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
panic("unknown return value from ProviderSet.For")
|
panic("unknown return value from ProviderSet.For")
|
||||||
}
|
}
|
||||||
@@ -275,11 +303,24 @@ func verifyArgsUsed(set *ProviderSet, used []*providerSetSrc) []error {
|
|||||||
errs = append(errs, fmt.Errorf("unused interface binding to type %s", types.TypeString(b.Iface, nil)))
|
errs = append(errs, fmt.Errorf("unused interface binding to type %s", types.TypeString(b.Iface, nil)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, f := range set.Fields {
|
||||||
|
found := false
|
||||||
|
for _, u := range used {
|
||||||
|
if u.Field == f {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
errs = append(errs, fmt.Errorf("unused field %q.%s", f.Parent, f.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildProviderMap creates the providerMap and srcMap fields for a given provider set.
|
// buildProviderMap creates the providerMap and srcMap fields for a given
|
||||||
// The given provider set's providerMap and srcMap fields are ignored.
|
// provider set. The given provider set's providerMap and srcMap fields are
|
||||||
|
// ignored.
|
||||||
func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *ProviderSet) (*typeutil.Map, *typeutil.Map, []error) {
|
func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *ProviderSet) (*typeutil.Map, *typeutil.Map, []error) {
|
||||||
providerMap := new(typeutil.Map)
|
providerMap := new(typeutil.Map)
|
||||||
providerMap.SetHasher(hasher)
|
providerMap.SetHasher(hasher)
|
||||||
@@ -339,6 +380,15 @@ func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *Provider
|
|||||||
providerMap.Set(v.Out, &ProvidedType{t: v.Out, v: v})
|
providerMap.Set(v.Out, &ProvidedType{t: v.Out, v: v})
|
||||||
srcMap.Set(v.Out, src)
|
srcMap.Set(v.Out, src)
|
||||||
}
|
}
|
||||||
|
for _, f := range set.Fields {
|
||||||
|
src := &providerSetSrc{Field: f}
|
||||||
|
if prevSrc := srcMap.At(f.Out); prevSrc != nil {
|
||||||
|
ec.add(bindingConflictError(fset, f.Out, set, src, prevSrc.(*providerSetSrc)))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
providerMap.Set(f.Out, &ProvidedType{t: f.Out, f: f})
|
||||||
|
srcMap.Set(f.Out, src)
|
||||||
|
}
|
||||||
if len(ec.errors) > 0 {
|
if len(ec.errors) > 0 {
|
||||||
return nil, nil, ec.errors
|
return nil, nil, ec.errors
|
||||||
}
|
}
|
||||||
@@ -398,27 +448,35 @@ func verifyAcyclic(providerMap *typeutil.Map, hasher typeutil.Hasher) []error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pt := x.(*ProvidedType)
|
pt := x.(*ProvidedType)
|
||||||
if pt.IsValue() {
|
switch {
|
||||||
|
case pt.IsValue():
|
||||||
// Leaf: values do not have dependencies.
|
// Leaf: values do not have dependencies.
|
||||||
continue
|
case pt.IsArg():
|
||||||
}
|
|
||||||
if pt.IsArg() {
|
|
||||||
// Injector arguments do not have dependencies.
|
// Injector arguments do not have dependencies.
|
||||||
continue
|
case pt.IsProvider() || pt.IsField():
|
||||||
}
|
var args []types.Type
|
||||||
if !pt.IsProvider() {
|
if pt.IsProvider() {
|
||||||
panic("invalid provider map value")
|
|
||||||
}
|
|
||||||
for _, arg := range pt.Provider().Args {
|
for _, arg := range pt.Provider().Args {
|
||||||
a := arg.Type
|
args = append(args, arg.Type)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = append(args, pt.Field().Parent)
|
||||||
|
}
|
||||||
|
for _, a := range args {
|
||||||
hasCycle := false
|
hasCycle := false
|
||||||
for i, b := range curr {
|
for i, b := range curr {
|
||||||
if types.Identical(a, b) {
|
if types.Identical(a, b) {
|
||||||
sb := new(strings.Builder)
|
sb := new(strings.Builder)
|
||||||
fmt.Fprintf(sb, "cycle for %s:\n", types.TypeString(a, nil))
|
fmt.Fprintf(sb, "cycle for %s:\n", types.TypeString(a, nil))
|
||||||
for j := i; j < len(curr); j++ {
|
for j := i; j < len(curr); j++ {
|
||||||
p := providerMap.At(curr[j]).(*ProvidedType).Provider()
|
t := providerMap.At(curr[j]).(*ProvidedType)
|
||||||
|
if t.IsProvider() {
|
||||||
|
p := t.Provider()
|
||||||
fmt.Fprintf(sb, "%s (%s.%s) ->\n", types.TypeString(curr[j], nil), p.Pkg.Path(), p.Name)
|
fmt.Fprintf(sb, "%s (%s.%s) ->\n", types.TypeString(curr[j], nil), p.Pkg.Path(), p.Name)
|
||||||
|
} else {
|
||||||
|
p := t.Field()
|
||||||
|
fmt.Fprintf(sb, "%s (%s.%s) ->\n", types.TypeString(curr[j], nil), p.Parent, p.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(sb, "%s", types.TypeString(a, nil))
|
fmt.Fprintf(sb, "%s", types.TypeString(a, nil))
|
||||||
ec.add(errors.New(sb.String()))
|
ec.add(errors.New(sb.String()))
|
||||||
@@ -431,6 +489,9 @@ func verifyAcyclic(providerMap *typeutil.Map, hasher typeutil.Hasher) []error {
|
|||||||
stk = append(stk, next)
|
stk = append(stk, next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
panic("invalid provider map value")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ec.errors
|
return ec.errors
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type providerSetSrc struct {
|
|||||||
Value *Value
|
Value *Value
|
||||||
Import *ProviderSet
|
Import *ProviderSet
|
||||||
InjectorArg *InjectorArg
|
InjectorArg *InjectorArg
|
||||||
|
Field *Field
|
||||||
}
|
}
|
||||||
|
|
||||||
// description returns a string describing the source of p, including line numbers.
|
// description returns a string describing the source of p, including line numbers.
|
||||||
@@ -63,6 +64,8 @@ func (p *providerSetSrc) description(fset *token.FileSet, typ types.Type) string
|
|||||||
case p.InjectorArg != nil:
|
case p.InjectorArg != nil:
|
||||||
args := p.InjectorArg.Args
|
args := p.InjectorArg.Args
|
||||||
return fmt.Sprintf("argument %s to injector function %s (%s)", args.Tuple.At(p.InjectorArg.Index).Name(), args.Name, fset.Position(args.Pos))
|
return fmt.Sprintf("argument %s to injector function %s (%s)", args.Tuple.At(p.InjectorArg.Index).Name(), args.Name, fset.Position(args.Pos))
|
||||||
|
case p.Field != nil:
|
||||||
|
return fmt.Sprintf("wire.FieldsOf (%s)", fset.Position(p.Field.Pos))
|
||||||
}
|
}
|
||||||
panic("providerSetSrc with no fields set")
|
panic("providerSetSrc with no fields set")
|
||||||
}
|
}
|
||||||
@@ -96,6 +99,7 @@ type ProviderSet struct {
|
|||||||
Providers []*Provider
|
Providers []*Provider
|
||||||
Bindings []*IfaceBinding
|
Bindings []*IfaceBinding
|
||||||
Values []*Value
|
Values []*Value
|
||||||
|
Fields []*Field
|
||||||
Imports []*ProviderSet
|
Imports []*ProviderSet
|
||||||
// InjectorArgs is only filled in for wire.Build.
|
// InjectorArgs is only filled in for wire.Build.
|
||||||
InjectorArgs *InjectorArgs
|
InjectorArgs *InjectorArgs
|
||||||
@@ -214,6 +218,21 @@ type InjectorArgs struct {
|
|||||||
Pos token.Pos
|
Pos token.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field describes a list of fields from a struct.
|
||||||
|
type Field struct {
|
||||||
|
// Parent is the struct or pointer to the struct that the field belongs to.
|
||||||
|
Parent types.Type
|
||||||
|
// Name is the field name.
|
||||||
|
Name string
|
||||||
|
// Pkg is the package that the struct resides in.
|
||||||
|
Pkg *types.Package
|
||||||
|
// Pos is the source position of the field declaration.
|
||||||
|
// defining these fields.
|
||||||
|
Pos token.Pos
|
||||||
|
// Out is the field's type.
|
||||||
|
Out types.Type
|
||||||
|
}
|
||||||
|
|
||||||
// Load finds all the provider sets in the packages that match the given
|
// Load finds all the provider sets in the packages that match the given
|
||||||
// patterns, as well as the provider sets' transitive dependencies. It
|
// patterns, as well as the provider sets' transitive dependencies. It
|
||||||
// may return both errors and Info. The patterns are defined by the
|
// may return both errors and Info. The patterns are defined by the
|
||||||
@@ -436,8 +455,8 @@ func newObjectCache(pkgs []*packages.Package) *objectCache {
|
|||||||
return oc
|
return oc
|
||||||
}
|
}
|
||||||
|
|
||||||
// get converts a Go object into a Wire structure. It may return a
|
// get converts a Go object into a Wire structure. It may return a *Provider, an
|
||||||
// *Provider, an *IfaceBinding, a *ProviderSet, or a *Value.
|
// *IfaceBinding, a *ProviderSet, a *Value, or a *Fields.
|
||||||
func (oc *objectCache) get(obj types.Object) (val interface{}, errs []error) {
|
func (oc *objectCache) get(obj types.Object) (val interface{}, errs []error) {
|
||||||
ref := objRef{
|
ref := objRef{
|
||||||
importPath: obj.Pkg().Path(),
|
importPath: obj.Pkg().Path(),
|
||||||
@@ -493,8 +512,8 @@ func (oc *objectCache) varDecl(obj *types.Var) *ast.ValueSpec {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processExpr converts an expression into a Wire structure. It may
|
// processExpr converts an expression into a Wire structure. It may return a
|
||||||
// return a *Provider, an *IfaceBinding, a *ProviderSet, or a *Value.
|
// *Provider, an *IfaceBinding, a *ProviderSet, a *Value or a *Field.
|
||||||
func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Expr, varName string) (interface{}, []error) {
|
func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Expr, varName string) (interface{}, []error) {
|
||||||
exprPos := oc.fset.Position(expr.Pos())
|
exprPos := oc.fset.Position(expr.Pos())
|
||||||
expr = astutil.Unparen(expr)
|
expr = astutil.Unparen(expr)
|
||||||
@@ -531,6 +550,12 @@ func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Ex
|
|||||||
return nil, []error{notePosition(exprPos, err)}
|
return nil, []error{notePosition(exprPos, err)}
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
|
case "FieldsOf":
|
||||||
|
v, err := processFieldsOf(oc.fset, info, call)
|
||||||
|
if err != nil {
|
||||||
|
return nil, []error{notePosition(exprPos, err)}
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
default:
|
default:
|
||||||
return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
|
return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
|
||||||
}
|
}
|
||||||
@@ -570,6 +595,8 @@ func (oc *objectCache) processNewSet(info *types.Info, pkgPath string, call *ast
|
|||||||
pset.Bindings = append(pset.Bindings, item)
|
pset.Bindings = append(pset.Bindings, item)
|
||||||
case *Value:
|
case *Value:
|
||||||
pset.Values = append(pset.Values, item)
|
pset.Values = append(pset.Values, item)
|
||||||
|
case []*Field:
|
||||||
|
pset.Fields = append(pset.Fields, item...)
|
||||||
default:
|
default:
|
||||||
panic("unknown item type")
|
panic("unknown item type")
|
||||||
}
|
}
|
||||||
@@ -845,6 +872,73 @@ func processInterfaceValue(fset *token.FileSet, info *types.Info, call *ast.Call
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// processFieldsOf creates a list of fields from a wire.FieldsOf call.
|
||||||
|
func processFieldsOf(fset *token.FileSet, info *types.Info, call *ast.CallExpr) ([]*Field, error) {
|
||||||
|
// Assumes that call.Fun is wire.FieldsOf.
|
||||||
|
|
||||||
|
if len(call.Args) < 2 {
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()),
|
||||||
|
errors.New("call to FieldsOf must specify fields to be extracted"))
|
||||||
|
}
|
||||||
|
const firstArgReqFormat = "first argument to FieldsOf must be a pointer to a struct or a pointer to a pointer to a struct; found %s"
|
||||||
|
structType := info.TypeOf(call.Args[0])
|
||||||
|
structPtr, ok := structType.(*types.Pointer)
|
||||||
|
if !ok {
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()),
|
||||||
|
fmt.Errorf(firstArgReqFormat, types.TypeString(structType, nil)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var struc *types.Struct
|
||||||
|
switch t := structPtr.Elem().Underlying().(type) {
|
||||||
|
case *types.Pointer:
|
||||||
|
struc, ok = t.Elem().Underlying().(*types.Struct)
|
||||||
|
if !ok {
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()),
|
||||||
|
fmt.Errorf(firstArgReqFormat, types.TypeString(struc, nil)))
|
||||||
|
}
|
||||||
|
case *types.Struct:
|
||||||
|
struc = t
|
||||||
|
default:
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()),
|
||||||
|
fmt.Errorf(firstArgReqFormat, types.TypeString(t, nil)))
|
||||||
|
}
|
||||||
|
if struc.NumFields() < len(call.Args)-1 {
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()),
|
||||||
|
fmt.Errorf("fields number exceeds the number available in the struct which has %d fields", struc.NumFields()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := make([]*Field, 0, len(call.Args)-1)
|
||||||
|
for i := 1; i < len(call.Args); i++ {
|
||||||
|
v, err := checkField(call.Args[i], struc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, notePosition(fset.Position(call.Pos()), err)
|
||||||
|
}
|
||||||
|
fields = append(fields, &Field{
|
||||||
|
Parent: structPtr.Elem(),
|
||||||
|
Name: v.Name(),
|
||||||
|
Pkg: v.Pkg(),
|
||||||
|
Pos: v.Pos(),
|
||||||
|
Out: v.Type(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkField reports whether f is a field of st. f should be a string with the
|
||||||
|
// field name.
|
||||||
|
func checkField(f ast.Expr, st *types.Struct) (*types.Var, error) {
|
||||||
|
b, ok := f.(*ast.BasicLit)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%v must be a string with the field name", f)
|
||||||
|
}
|
||||||
|
for i := 0; i < st.NumFields(); i++ {
|
||||||
|
if strings.EqualFold(strconv.Quote(st.Field(i).Name()), b.Value) {
|
||||||
|
return st.Field(i), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%s is not a field of %s", b.Value, st.String())
|
||||||
|
}
|
||||||
|
|
||||||
// findInjectorBuild returns the wire.Build call if fn is an injector template.
|
// findInjectorBuild returns the wire.Build call if fn is an injector template.
|
||||||
// It returns nil if the function is not an injector template.
|
// It returns nil if the function is not an injector template.
|
||||||
func findInjectorBuild(info *types.Info, fn *ast.FuncDecl) (*ast.CallExpr, error) {
|
func findInjectorBuild(info *types.Info, fn *ast.FuncDecl) (*ast.CallExpr, error) {
|
||||||
@@ -928,11 +1022,12 @@ type ProvidedType struct {
|
|||||||
p *Provider
|
p *Provider
|
||||||
v *Value
|
v *Value
|
||||||
a *InjectorArg
|
a *InjectorArg
|
||||||
|
f *Field
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNil reports whether pt is the zero value.
|
// IsNil reports whether pt is the zero value.
|
||||||
func (pt ProvidedType) IsNil() bool {
|
func (pt ProvidedType) IsNil() bool {
|
||||||
return pt.p == nil && pt.v == nil && pt.a == nil
|
return pt.p == nil && pt.v == nil && pt.a == nil && pt.f == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns the output type.
|
// Type returns the output type.
|
||||||
@@ -961,6 +1056,11 @@ func (pt ProvidedType) IsArg() bool {
|
|||||||
return pt.a != nil
|
return pt.a != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsField reports whether pt points to a Fields.
|
||||||
|
func (pt ProvidedType) IsField() bool {
|
||||||
|
return pt.f != nil
|
||||||
|
}
|
||||||
|
|
||||||
// Provider returns pt as a Provider pointer. It panics if pt does not point
|
// Provider returns pt as a Provider pointer. It panics if pt does not point
|
||||||
// to a Provider.
|
// to a Provider.
|
||||||
func (pt ProvidedType) Provider() *Provider {
|
func (pt ProvidedType) Provider() *Provider {
|
||||||
@@ -987,3 +1087,12 @@ func (pt ProvidedType) Arg() *InjectorArg {
|
|||||||
}
|
}
|
||||||
return pt.a
|
return pt.a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field returns pt as a Field pointer. It panics if pt does not point to a
|
||||||
|
// struct Field.
|
||||||
|
func (pt ProvidedType) Field() *Field {
|
||||||
|
if pt.f == nil {
|
||||||
|
panic("ProvidedType does not hold a Field")
|
||||||
|
}
|
||||||
|
return pt.f
|
||||||
|
}
|
||||||
|
|||||||
38
internal/wire/testdata/FieldsOfCycle/foo/foo.go
vendored
Normal file
38
internal/wire/testdata/FieldsOfCycle/foo/foo.go
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(injectedBaz())
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo int
|
||||||
|
type Baz int
|
||||||
|
|
||||||
|
type Bar struct {
|
||||||
|
Bz Baz
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideFoo(_ Baz) Foo {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideBar(_ Foo) Bar {
|
||||||
|
return Bar{}
|
||||||
|
}
|
||||||
26
internal/wire/testdata/FieldsOfCycle/foo/wire.go
vendored
Normal file
26
internal/wire/testdata/FieldsOfCycle/foo/wire.go
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func injectedBaz() Baz {
|
||||||
|
wire.Build(provideFoo, provideBar, wire.FieldsOf(new(Bar), "Bz"))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
1
internal/wire/testdata/FieldsOfCycle/pkg
vendored
Normal file
1
internal/wire/testdata/FieldsOfCycle/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
example.com/foo
|
||||||
5
internal/wire/testdata/FieldsOfCycle/want/wire_errs.txt
vendored
Normal file
5
internal/wire/testdata/FieldsOfCycle/want/wire_errs.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
example.com/foo/wire.go:x:y: cycle for example.com/foo.Bar:
|
||||||
|
example.com/foo.Bar (example.com/foo.provideBar) ->
|
||||||
|
example.com/foo.Foo (example.com/foo.provideFoo) ->
|
||||||
|
example.com/foo.Baz (example.com/foo.Bar.Bz) ->
|
||||||
|
example.com/foo.Bar
|
||||||
32
internal/wire/testdata/FieldsOfImportedStruct/bar/bar.go
vendored
Normal file
32
internal/wire/testdata/FieldsOfImportedStruct/bar/bar.go
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package bar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
V int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Cfg *Config
|
||||||
|
F *foo.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *Config, f *foo.Service) *Service {
|
||||||
|
return &Service{Cfg: cfg, F: f}
|
||||||
|
}
|
||||||
36
internal/wire/testdata/FieldsOfImportedStruct/baz/baz.go
vendored
Normal file
36
internal/wire/testdata/FieldsOfImportedStruct/baz/baz.go
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package baz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Foo *foo.Config
|
||||||
|
Bar *bar.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Foo *foo.Service
|
||||||
|
Bar *bar.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Service) String() string {
|
||||||
|
return fmt.Sprintf("%d %d", m.Foo.Cfg.V, m.Bar.Cfg.V)
|
||||||
|
}
|
||||||
27
internal/wire/testdata/FieldsOfImportedStruct/foo/foo.go
vendored
Normal file
27
internal/wire/testdata/FieldsOfImportedStruct/foo/foo.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
V int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Cfg *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *Config) *Service {
|
||||||
|
return &Service{Cfg: cfg}
|
||||||
|
}
|
||||||
49
internal/wire/testdata/FieldsOfImportedStruct/main/wire.go
vendored
Normal file
49
internal/wire/testdata/FieldsOfImportedStruct/main/wire.go
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/baz"
|
||||||
|
"example.com/foo"
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newBazService(*baz.Config) *baz.Service {
|
||||||
|
wire.Build(
|
||||||
|
baz.Service{},
|
||||||
|
wire.FieldsOf(
|
||||||
|
new(*baz.Config),
|
||||||
|
"Foo",
|
||||||
|
"Bar",
|
||||||
|
),
|
||||||
|
foo.New,
|
||||||
|
bar.New,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := &baz.Config{
|
||||||
|
Foo: &foo.Config{1},
|
||||||
|
Bar: &bar.Config{2},
|
||||||
|
}
|
||||||
|
svc := newBazService(cfg)
|
||||||
|
fmt.Println(svc.String())
|
||||||
|
}
|
||||||
1
internal/wire/testdata/FieldsOfImportedStruct/pkg
vendored
Normal file
1
internal/wire/testdata/FieldsOfImportedStruct/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
example.com/main
|
||||||
1
internal/wire/testdata/FieldsOfImportedStruct/want/program_out.txt
vendored
Normal file
1
internal/wire/testdata/FieldsOfImportedStruct/want/program_out.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1 2
|
||||||
38
internal/wire/testdata/FieldsOfImportedStruct/want/wire_gen.go
vendored
Normal file
38
internal/wire/testdata/FieldsOfImportedStruct/want/wire_gen.go
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Code generated by Wire. DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate wire
|
||||||
|
//+build !wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/baz"
|
||||||
|
"example.com/foo"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Injectors from wire.go:
|
||||||
|
|
||||||
|
func newBazService(config *baz.Config) *baz.Service {
|
||||||
|
fooConfig := config.Foo
|
||||||
|
service := foo.New(fooConfig)
|
||||||
|
barConfig := config.Bar
|
||||||
|
barService := bar.New(barConfig, service)
|
||||||
|
bazService := &baz.Service{
|
||||||
|
Foo: service,
|
||||||
|
Bar: barService,
|
||||||
|
}
|
||||||
|
return bazService
|
||||||
|
}
|
||||||
|
|
||||||
|
// wire.go:
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := &baz.Config{
|
||||||
|
Foo: &foo.Config{1},
|
||||||
|
Bar: &bar.Config{2},
|
||||||
|
}
|
||||||
|
svc := newBazService(cfg)
|
||||||
|
fmt.Println(svc.String())
|
||||||
|
}
|
||||||
29
internal/wire/testdata/FieldsOfStruct/foo/foo.go
vendored
Normal file
29
internal/wire/testdata/FieldsOfStruct/foo/foo.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2018 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
Foo string
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideS() S {
|
||||||
|
return S{Foo: "Hello, World!"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(injectedMessage())
|
||||||
|
}
|
||||||
28
internal/wire/testdata/FieldsOfStruct/foo/wire.go
vendored
Normal file
28
internal/wire/testdata/FieldsOfStruct/foo/wire.go
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2018 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func injectedMessage() string {
|
||||||
|
wire.Build(
|
||||||
|
provideS,
|
||||||
|
wire.FieldsOf(new(S), "Foo"))
|
||||||
|
return ""
|
||||||
|
}
|
||||||
1
internal/wire/testdata/FieldsOfStruct/pkg
vendored
Normal file
1
internal/wire/testdata/FieldsOfStruct/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
example.com/foo
|
||||||
1
internal/wire/testdata/FieldsOfStruct/want/program_out.txt
vendored
Normal file
1
internal/wire/testdata/FieldsOfStruct/want/program_out.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello, World!
|
||||||
14
internal/wire/testdata/FieldsOfStruct/want/wire_gen.go
vendored
Normal file
14
internal/wire/testdata/FieldsOfStruct/want/wire_gen.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Code generated by Wire. DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate wire
|
||||||
|
//+build !wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Injectors from wire.go:
|
||||||
|
|
||||||
|
func injectedMessage() string {
|
||||||
|
s := provideS()
|
||||||
|
string2 := s.Foo
|
||||||
|
return string2
|
||||||
|
}
|
||||||
29
internal/wire/testdata/FieldsOfStructPointer/foo/foo.go
vendored
Normal file
29
internal/wire/testdata/FieldsOfStructPointer/foo/foo.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2018 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
Foo string
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideS() *S {
|
||||||
|
return &S{Foo: "Hello, World!"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(injectedMessage())
|
||||||
|
}
|
||||||
28
internal/wire/testdata/FieldsOfStructPointer/foo/wire.go
vendored
Normal file
28
internal/wire/testdata/FieldsOfStructPointer/foo/wire.go
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2018 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func injectedMessage() string {
|
||||||
|
wire.Build(
|
||||||
|
provideS,
|
||||||
|
wire.FieldsOf(new(*S), "Foo"))
|
||||||
|
return ""
|
||||||
|
}
|
||||||
1
internal/wire/testdata/FieldsOfStructPointer/pkg
vendored
Normal file
1
internal/wire/testdata/FieldsOfStructPointer/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
example.com/foo
|
||||||
1
internal/wire/testdata/FieldsOfStructPointer/want/program_out.txt
vendored
Normal file
1
internal/wire/testdata/FieldsOfStructPointer/want/program_out.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello, World!
|
||||||
14
internal/wire/testdata/FieldsOfStructPointer/want/wire_gen.go
vendored
Normal file
14
internal/wire/testdata/FieldsOfStructPointer/want/wire_gen.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Code generated by Wire. DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate wire
|
||||||
|
//+build !wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Injectors from wire.go:
|
||||||
|
|
||||||
|
func injectedMessage() string {
|
||||||
|
s := provideS()
|
||||||
|
string2 := s.Foo
|
||||||
|
return string2
|
||||||
|
}
|
||||||
32
internal/wire/testdata/FieldsOfValueStruct/bar/bar.go
vendored
Normal file
32
internal/wire/testdata/FieldsOfValueStruct/bar/bar.go
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package bar
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
V int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Cfg *Config
|
||||||
|
F *foo.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *Config, f *foo.Service) *Service {
|
||||||
|
return &Service{Cfg: cfg, F: f}
|
||||||
|
}
|
||||||
36
internal/wire/testdata/FieldsOfValueStruct/baz/baz.go
vendored
Normal file
36
internal/wire/testdata/FieldsOfValueStruct/baz/baz.go
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package baz
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Foo *foo.Config
|
||||||
|
Bar *bar.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Foo *foo.Service
|
||||||
|
Bar *bar.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Service) String() string {
|
||||||
|
return fmt.Sprintf("%d %d", m.Foo.Cfg.V, m.Bar.Cfg.V)
|
||||||
|
}
|
||||||
27
internal/wire/testdata/FieldsOfValueStruct/foo/foo.go
vendored
Normal file
27
internal/wire/testdata/FieldsOfValueStruct/foo/foo.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package foo
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
V int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Cfg *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *Config) *Service {
|
||||||
|
return &Service{Cfg: cfg}
|
||||||
|
}
|
||||||
49
internal/wire/testdata/FieldsOfValueStruct/main/wire.go
vendored
Normal file
49
internal/wire/testdata/FieldsOfValueStruct/main/wire.go
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2019 The Wire Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/baz"
|
||||||
|
"example.com/foo"
|
||||||
|
"github.com/google/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newBazService() *baz.Service {
|
||||||
|
wire.Build(
|
||||||
|
baz.Service{},
|
||||||
|
wire.Value(&baz.Config{
|
||||||
|
Foo: &foo.Config{1},
|
||||||
|
Bar: &bar.Config{2},
|
||||||
|
}),
|
||||||
|
wire.FieldsOf(
|
||||||
|
new(*baz.Config),
|
||||||
|
"Foo",
|
||||||
|
"Bar",
|
||||||
|
),
|
||||||
|
foo.New,
|
||||||
|
bar.New,
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
svc := newBazService()
|
||||||
|
fmt.Println(svc.String())
|
||||||
|
}
|
||||||
1
internal/wire/testdata/FieldsOfValueStruct/pkg
vendored
Normal file
1
internal/wire/testdata/FieldsOfValueStruct/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
example.com/main
|
||||||
1
internal/wire/testdata/FieldsOfValueStruct/want/program_out.txt
vendored
Normal file
1
internal/wire/testdata/FieldsOfValueStruct/want/program_out.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1 2
|
||||||
42
internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go
vendored
Normal file
42
internal/wire/testdata/FieldsOfValueStruct/want/wire_gen.go
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Code generated by Wire. DO NOT EDIT.
|
||||||
|
|
||||||
|
//go:generate wire
|
||||||
|
//+build !wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"example.com/bar"
|
||||||
|
"example.com/baz"
|
||||||
|
"example.com/foo"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Injectors from wire.go:
|
||||||
|
|
||||||
|
func newBazService() *baz.Service {
|
||||||
|
config := _wireConfigValue
|
||||||
|
fooConfig := config.Foo
|
||||||
|
service := foo.New(fooConfig)
|
||||||
|
barConfig := config.Bar
|
||||||
|
barService := bar.New(barConfig, service)
|
||||||
|
bazService := &baz.Service{
|
||||||
|
Foo: service,
|
||||||
|
Bar: barService,
|
||||||
|
}
|
||||||
|
return bazService
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_wireConfigValue = &baz.Config{
|
||||||
|
Foo: &foo.Config{1},
|
||||||
|
Bar: &bar.Config{2},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// wire.go:
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
svc := newBazService()
|
||||||
|
fmt.Println(svc.String())
|
||||||
|
}
|
||||||
@@ -28,22 +28,28 @@ import (
|
|||||||
type MainConfig struct {
|
type MainConfig struct {
|
||||||
Foo *foo.Config
|
Foo *foo.Config
|
||||||
Bar *bar.Config
|
Bar *bar.Config
|
||||||
Baz *baz.Config
|
baz *baz.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainService struct {
|
type MainService struct {
|
||||||
Foo *foo.Service
|
Foo *foo.Service
|
||||||
Bar *bar.Service
|
Bar *bar.Service
|
||||||
Baz *baz.Service
|
baz *baz.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainService) String() string {
|
func (m *MainService) String() string {
|
||||||
return fmt.Sprintf("%d %d %d", m.Foo.Cfg.V, m.Bar.Cfg.V, m.Baz.Cfg.V)
|
return fmt.Sprintf("%d %d %d", m.Foo.Cfg.V, m.Bar.Cfg.V, m.baz.Cfg.V)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMainService(*foo.Config, *bar.Config, *baz.Config) *MainService {
|
func newMainService(MainConfig) *MainService {
|
||||||
wire.Build(
|
wire.Build(
|
||||||
MainService{},
|
MainService{},
|
||||||
|
wire.FieldsOf(
|
||||||
|
new(MainConfig),
|
||||||
|
"Foo",
|
||||||
|
"Bar",
|
||||||
|
"baz",
|
||||||
|
),
|
||||||
foo.New,
|
foo.New,
|
||||||
bar.New,
|
bar.New,
|
||||||
baz.New,
|
baz.New,
|
||||||
@@ -52,11 +58,11 @@ func newMainService(*foo.Config, *bar.Config, *baz.Config) *MainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg := &MainConfig{
|
cfg := MainConfig{
|
||||||
Foo: &foo.Config{1},
|
Foo: &foo.Config{1},
|
||||||
Bar: &bar.Config{2},
|
Bar: &bar.Config{2},
|
||||||
Baz: &baz.Config{3},
|
baz: &baz.Config{3},
|
||||||
}
|
}
|
||||||
svc := newMainService(cfg.Foo, cfg.Bar, cfg.Baz)
|
svc := newMainService(cfg)
|
||||||
fmt.Println(svc.String())
|
fmt.Println(svc.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,14 +14,17 @@ import (
|
|||||||
|
|
||||||
// Injectors from wire.go:
|
// Injectors from wire.go:
|
||||||
|
|
||||||
func newMainService(config *foo.Config, barConfig *bar.Config, bazConfig *baz.Config) *MainService {
|
func newMainService(mainConfig MainConfig) *MainService {
|
||||||
|
config := mainConfig.Foo
|
||||||
service := foo.New(config)
|
service := foo.New(config)
|
||||||
|
barConfig := mainConfig.Bar
|
||||||
barService := bar.New(barConfig, service)
|
barService := bar.New(barConfig, service)
|
||||||
|
bazConfig := mainConfig.baz
|
||||||
bazService := baz.New(bazConfig, barService)
|
bazService := baz.New(bazConfig, barService)
|
||||||
mainService := &MainService{
|
mainService := &MainService{
|
||||||
Foo: service,
|
Foo: service,
|
||||||
Bar: barService,
|
Bar: barService,
|
||||||
Baz: bazService,
|
baz: bazService,
|
||||||
}
|
}
|
||||||
return mainService
|
return mainService
|
||||||
}
|
}
|
||||||
@@ -31,25 +34,25 @@ func newMainService(config *foo.Config, barConfig *bar.Config, bazConfig *baz.Co
|
|||||||
type MainConfig struct {
|
type MainConfig struct {
|
||||||
Foo *foo.Config
|
Foo *foo.Config
|
||||||
Bar *bar.Config
|
Bar *bar.Config
|
||||||
Baz *baz.Config
|
baz *baz.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainService struct {
|
type MainService struct {
|
||||||
Foo *foo.Service
|
Foo *foo.Service
|
||||||
Bar *bar.Service
|
Bar *bar.Service
|
||||||
Baz *baz.Service
|
baz *baz.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MainService) String() string {
|
func (m *MainService) String() string {
|
||||||
return fmt.Sprintf("%d %d %d", m.Foo.Cfg.V, m.Bar.Cfg.V, m.Baz.Cfg.V)
|
return fmt.Sprintf("%d %d %d", m.Foo.Cfg.V, m.Bar.Cfg.V, m.baz.Cfg.V)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg := &MainConfig{
|
cfg := MainConfig{
|
||||||
Foo: &foo.Config{1},
|
Foo: &foo.Config{1},
|
||||||
Bar: &bar.Config{2},
|
Bar: &bar.Config{2},
|
||||||
Baz: &baz.Config{3},
|
baz: &baz.Config{3},
|
||||||
}
|
}
|
||||||
svc := newMainService(cfg.Foo, cfg.Bar, cfg.Baz)
|
svc := newMainService(cfg)
|
||||||
fmt.Println(svc.String())
|
fmt.Println(svc.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,3 +69,9 @@ func provideOneOfTwo() OneOfTwo {
|
|||||||
func provideTwoOfTwo() TwoOfTwo {
|
func provideTwoOfTwo() TwoOfTwo {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
Cfg Config
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config int
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ func injectBar() Bar {
|
|||||||
wire.Value("unused"), // not needed -> error
|
wire.Value("unused"), // not needed -> error
|
||||||
unusedSet, // nothing in set is needed -> error
|
unusedSet, // nothing in set is needed -> error
|
||||||
wire.Bind((*Fooer)(nil), (*Foo)(nil)), // binding to Fooer is not needed -> error
|
wire.Bind((*Fooer)(nil), (*Foo)(nil)), // binding to Fooer is not needed -> error
|
||||||
|
wire.FieldsOf(new(S), "Cfg"), // S.Cfg not needed -> error
|
||||||
)
|
)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ example.com/foo/wire.go:x:y: inject injectBar: unused provider "provideUnused"
|
|||||||
example.com/foo/wire.go:x:y: inject injectBar: unused value of type string
|
example.com/foo/wire.go:x:y: inject injectBar: unused value of type string
|
||||||
|
|
||||||
example.com/foo/wire.go:x:y: inject injectBar: unused interface binding to type example.com/foo.Fooer
|
example.com/foo/wire.go:x:y: inject injectBar: unused interface binding to type example.com/foo.Fooer
|
||||||
|
|
||||||
|
example.com/foo/wire.go:x:y: inject injectBar: unused field "example.com/foo.S".Cfg
|
||||||
@@ -623,6 +623,8 @@ func injectPass(name string, sig *types.Signature, calls []call, ig *injectorGen
|
|||||||
ig.funcProviderCall(lname, c, injectSig)
|
ig.funcProviderCall(lname, c, injectSig)
|
||||||
case valueExpr:
|
case valueExpr:
|
||||||
ig.valueExpr(lname, c)
|
ig.valueExpr(lname, c)
|
||||||
|
case selectorExpr:
|
||||||
|
ig.fieldExpr(lname, c)
|
||||||
default:
|
default:
|
||||||
panic("unknown kind")
|
panic("unknown kind")
|
||||||
}
|
}
|
||||||
@@ -715,6 +717,15 @@ func (ig *injectorGen) valueExpr(lname string, c *call) {
|
|||||||
ig.p("\t%s := %s\n", lname, ig.g.values[c.valueExpr])
|
ig.p("\t%s := %s\n", lname, ig.g.values[c.valueExpr])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ig *injectorGen) fieldExpr(lname string, c *call) {
|
||||||
|
a := c.args[0]
|
||||||
|
if a < len(ig.paramNames) {
|
||||||
|
ig.p("\t%s := %s.%s\n", lname, ig.paramNames[a], c.name)
|
||||||
|
} else {
|
||||||
|
ig.p("\t%s := %s.%s\n", lname, ig.localNames[a-len(ig.paramNames)], c.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nameInInjector reports whether name collides with any other identifier
|
// nameInInjector reports whether name collides with any other identifier
|
||||||
// in the current injector.
|
// in the current injector.
|
||||||
func (ig *injectorGen) nameInInjector(name string) bool {
|
func (ig *injectorGen) nameInInjector(name string) bool {
|
||||||
|
|||||||
28
wire.go
28
wire.go
@@ -30,7 +30,8 @@ type ProviderSet struct{}
|
|||||||
|
|
||||||
// NewSet creates a new provider set that includes the providers in its
|
// NewSet creates a new provider set that includes the providers in its
|
||||||
// arguments. Each argument is a function value, a struct (zero) value, a
|
// arguments. Each argument is a function value, a struct (zero) value, a
|
||||||
// provider set, a call to Bind, a call to Value, or a call to InterfaceValue.
|
// provider set, a call to Bind, a call to Value, a call to InterfaceValue or a
|
||||||
|
// call to FieldsOf.
|
||||||
//
|
//
|
||||||
// Passing a function value to NewSet declares that the function's first
|
// Passing a function value to NewSet declares that the function's first
|
||||||
// return value type will be provided by calling the function. The arguments
|
// return value type will be provided by calling the function. The arguments
|
||||||
@@ -135,3 +136,28 @@ func Value(interface{}) ProvidedValue {
|
|||||||
func InterfaceValue(typ interface{}, x interface{}) ProvidedValue {
|
func InterfaceValue(typ interface{}, x interface{}) ProvidedValue {
|
||||||
return ProvidedValue{}
|
return ProvidedValue{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StructFields is a collection of the fields from a struct.
|
||||||
|
type StructFields struct{}
|
||||||
|
|
||||||
|
// FieldsOf declares that the fields named of the given struct type will be used
|
||||||
|
// to provide the types of those fields. The structType argument must be a
|
||||||
|
// pointer to the struct or a pointer to a pointer to the struct it wishes to reference.
|
||||||
|
//
|
||||||
|
// The following example would provide *Foo and *Bar using S.MyFoo and S.MyBar respectively:
|
||||||
|
//
|
||||||
|
// type S struct {
|
||||||
|
// MyFoo *Foo
|
||||||
|
// MyBar *Bar
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func NewStruct() S { /* ... */ }
|
||||||
|
// var Set = wire.NewSet(wire.FieldsOf(new(S), "MyFoo", "MyBar"))
|
||||||
|
//
|
||||||
|
// or
|
||||||
|
//
|
||||||
|
// func NewStruct() *S { /* ... */ }
|
||||||
|
// var Set = wire.NewSet(wire.FieldsOf(new(*S), "MyFoo", "MyBar"))
|
||||||
|
func FieldsOf(structType interface{}, fieldNames ...string) StructFields {
|
||||||
|
return StructFields{}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user