goose: add goose.Value directive

Subsumes previous usage of goose.Optional.

Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Tuo Shan <shantuo@google.com>
This commit is contained in:
Ross Light
2018-05-04 12:44:53 -04:00
parent 235a7d8f80
commit 10676a814b
37 changed files with 706 additions and 60 deletions

View File

@@ -304,6 +304,33 @@ func injectFooBar() FooBar {
And similarly if the injector needed a `*FooBar`.
### Binding Values
Occasionally, it is useful to bind a basic value (usually `nil`) to a type.
Instead of having injectors depend on a throwaway provider function, you can
add a value expression to a provider set.
```go
type Foo int
func injectFoo() Foo {
panic(goose.Use(goose.Value(Foo(42))))
}
```
The generated injector would look like this:
```go
func injectFoo() Foo {
foo := Foo(42)
return foo
}
```
It's important to note that the expression will be copied, so references to
variables will be evaluated during the call to the injector. goose will emit
an error if the expression calls any functions.
### Cleanup functions
If a provider creates a value that needs to be cleaned up (e.g. closing a file),

View File

@@ -132,6 +132,8 @@ func show(pkgs ...string) error {
switch v := v.(type) {
case *goose.Provider:
out[types.TypeString(t, nil)] = v.Pos
case *goose.Value:
out[types.TypeString(t, nil)] = v.Pos
case *goose.IfaceBinding:
out[types.TypeString(t, nil)] = v.Pos
default:
@@ -150,7 +152,7 @@ func show(pkgs ...string) error {
type outGroup struct {
name string
inputs *typeutil.Map // values are not important
outputs *typeutil.Map // values are either *goose.Provider or *goose.IfaceBinding
outputs *typeutil.Map // values are *goose.Provider, *goose.Value, or *goose.IfaceBinding
}
// gather flattens a provider set into outputs grouped by the inputs
@@ -180,6 +182,9 @@ func gather(info *goose.Info, key goose.ProviderSetID) (_ []outGroup, imports ma
for _, b := range curr.Bindings {
pm.Set(b.Iface, b)
}
for _, v := range curr.Values {
pm.Set(v.Out, v)
}
for _, imp := range curr.Imports {
next = append(next, imp)
}
@@ -253,6 +258,24 @@ func gather(info *goose.Info, key goose.ProviderSetID) (_ []outGroup, imports ma
inputs: in,
outputs: out,
})
case *goose.Value:
for i := range groups {
if groups[i].inputs.Len() == 0 {
groups[i].outputs.Set(p.Out, p)
inputVisited.Set(p.Out, i)
continue dfs
}
}
in := new(typeutil.Map)
in.SetHasher(hash)
out := new(typeutil.Map)
out.SetHasher(hash)
out.Set(p.Out, p)
inputVisited.Set(p.Out, len(groups))
groups = append(groups, outGroup{
inputs: in,
outputs: out,
})
case *goose.IfaceBinding:
i, ok := inputVisited.At(p.Provided).(int)
if !ok {

View File

@@ -50,3 +50,15 @@ type Binding struct{}
func Bind(iface, to interface{}) Binding {
return Binding{}
}
// A ProvidedValue is an expression that is copied to the generated injector.
type ProvidedValue struct{}
// Value binds an expression to provide the type of the expression.
//
// Example:
//
// var MySet = goose.NewSet(goose.Value([]string(nil)))
func Value(interface{}) ProvidedValue {
return ProvidedValue{}
}

View File

@@ -16,17 +16,34 @@ package goose
import (
"fmt"
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/go/types/typeutil"
)
type callKind int
const (
funcProviderCall callKind = iota
structProvider
valueExpr
)
// A call represents a step of an injector function. It may be either a
// function call or a composite struct literal, depending on the value
// of isStruct.
// of kind.
type call struct {
// importPath and name identify the provider to call.
// kind indicates the code pattern to use.
kind callKind
// out is the type this step produces.
out types.Type
// importPath and name identify the provider to call for kind ==
// funcProviderCall or the type to construct for kind ==
// structProvider.
importPath string
name string
@@ -34,24 +51,29 @@ type call struct {
// a) one of the givens (args[i] < len(given)),
// b) the result of a previous provider call (args[i] >= len(given)), or
// c) the zero value for the type (args[i] == -1).
//
// This will be nil for kind == valueExpr.
args []int
// isStruct indicates whether this should generate a struct composite
// literal instead of a function call.
isStruct bool
// fieldNames maps the arguments to struct field names.
// This will only be set if isStruct is true.
// This will only be set if kind == structProvider.
fieldNames []string
// ins is the list of types this call receives as arguments.
// This will be nil for kind == valueExpr.
ins []types.Type
// out is the type produced by this provider call.
out types.Type
// The following are only set for kind == funcProviderCall:
// hasCleanup is true if the provider call returns a cleanup function.
hasCleanup bool
// hasErr is true if the provider call returns an error.
hasErr bool
// The following are only set for kind == valueExpr:
valueExpr ast.Expr
valueTypeInfo *types.Info
}
// solve finds the sequence of calls required to produce an output type
@@ -97,14 +119,14 @@ func solve(fset *token.FileSet, out types.Type, given []types.Type, set *Provide
}
}
p, _ := providers.At(typ).(*Provider)
if p == nil {
switch p := providers.At(typ).(type) {
case nil:
if len(trail) == 1 {
return fmt.Errorf("no provider found for %s (output of injector)", types.TypeString(typ, nil))
}
// TODO(light): Give name of provider.
return fmt.Errorf("no provider found for %s (required by provider of %s)", types.TypeString(typ, nil), types.TypeString(trail[len(trail)-2].Type, nil))
}
case *Provider:
if !types.Identical(p.Out, typ) {
// Interface binding. Don't create a call ourselves.
if err := visit(append(trail, ProviderInput{Type: p.Out})); err != nil {
@@ -123,24 +145,43 @@ func solve(fset *token.FileSet, out types.Type, given []types.Type, set *Provide
ins := make([]types.Type, len(p.Args))
for i := range p.Args {
ins[i] = p.Args[i].Type
if x := index.At(p.Args[i].Type); x != nil {
args[i] = x.(int)
} else {
args[i] = -1
}
args[i] = index.At(p.Args[i].Type).(int)
}
index.Set(typ, len(given)+len(calls))
kind := funcProviderCall
if p.IsStruct {
kind = structProvider
}
calls = append(calls, call{
kind: kind,
importPath: p.ImportPath,
name: p.Name,
args: args,
isStruct: p.IsStruct,
fieldNames: p.Fields,
ins: ins,
out: typ,
hasCleanup: p.HasCleanup,
hasErr: p.HasErr,
})
case *Value:
if !types.Identical(p.Out, typ) {
// Interface binding. Don't create a call ourselves.
if err := visit(append(trail, ProviderInput{Type: p.Out})); err != nil {
return err
}
index.Set(typ, index.At(p.Out))
return nil
}
index.Set(typ, len(given)+len(calls))
calls = append(calls, call{
kind: valueExpr,
out: typ,
valueExpr: p.expr,
valueTypeInfo: p.info,
})
default:
panic("unknown provider map value type")
}
return nil
}
if err := visit([]ProviderInput{{Type: out}}); err != nil {
@@ -155,7 +196,7 @@ func buildProviderMap(fset *token.FileSet, set *ProviderSet) (*typeutil.Map, err
set *ProviderSet
}
providerMap := new(typeutil.Map) // to *Provider
providerMap := new(typeutil.Map) // to *Provider or *Value
setMap := new(typeutil.Map) // to *ProviderSet, for error messages
var bindings []binding
visited := make(map[*ProviderSet]struct{})
@@ -175,6 +216,13 @@ func buildProviderMap(fset *token.FileSet, set *ProviderSet) (*typeutil.Map, err
providerMap.Set(p.Out, p)
setMap.Set(p.Out, curr)
}
for _, v := range curr.Values {
if providerMap.At(v.Out) != nil {
return nil, bindingConflictError(fset, v.Pos, v.Out, setMap.At(v.Out).(*ProviderSet))
}
providerMap.Set(v.Out, v)
setMap.Set(v.Out, curr)
}
for _, b := range curr.Bindings {
bindings = append(bindings, binding{
IfaceBinding: b,

View File

@@ -244,16 +244,25 @@ func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set
paramTypes[i] = types.TypeString(params.At(i).Type(), g.qualifyPkg)
}
for _, c := range calls {
switch c.kind {
case funcProviderCall:
g.qualifyImport(c.importPath)
if !c.isStruct {
// Struct providers just omit zero-valued fields.
continue
}
for i := range c.args {
if c.args[i] == -1 {
zeroValue(c.ins[i], g.qualifyPkg)
}
}
case structProvider:
g.qualifyImport(c.importPath)
case valueExpr:
if err := accessibleFrom(c.valueTypeInfo, c.valueExpr, g.currPackage); err != nil {
// TODO(light): Display line number of value expression.
ts := types.TypeString(c.out, nil)
return fmt.Errorf("inject %s: value %s can't be used: %v", name, ts, err)
}
default:
panic("unknown kind")
}
}
outTypeString := types.TypeString(outType, g.qualifyPkg)
zv := zeroValue(outType, g.qualifyPkg)
@@ -326,7 +335,8 @@ func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set
g.p(", %s", errVar)
}
g.p(" := ")
if c.isStruct {
switch c.kind {
case structProvider:
if _, ok := c.out.(*types.Pointer); ok {
g.p("&")
}
@@ -345,7 +355,7 @@ func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set
g.p(",\n")
}
g.p("\t}\n")
} else {
case funcProviderCall:
g.p("%s(", g.qualifiedID(c.importPath, c.name))
for j, a := range c.args {
if j > 0 {
@@ -360,6 +370,11 @@ func (g *gen) inject(fset *token.FileSet, name string, sig *types.Signature, set
}
}
g.p(")\n")
case valueExpr:
g.writeAST(fset, c.valueTypeInfo, c.valueExpr)
g.p("\n")
default:
panic("unknown kind")
}
if c.hasErr {
g.p("\tif %s != nil {\n", errVar)
@@ -656,6 +671,32 @@ func disambiguate(name string, collides func(string) bool) string {
}
}
// accessibleFrom reports whether node can be copied to wantPkg without
// violating Go visibility rules.
func accessibleFrom(info *types.Info, node ast.Node, wantPkg string) error {
var unexportError error
ast.Inspect(node, func(node ast.Node) bool {
if unexportError != nil {
return false
}
ident, ok := node.(*ast.Ident)
if !ok {
return true
}
obj := info.ObjectOf(ident)
if _, ok := obj.(*types.PkgName); ok {
// Local package names are fine, since we can just reimport them.
return true
}
if pkg := obj.Pkg(); pkg != nil && !ast.IsExported(ident.Name) && pkg.Path() != wantPkg {
unexportError = fmt.Errorf("uses unexported identifier %s", obj.Name())
return false
}
return true
})
return unexportError
}
var (
errorType = types.Universe.Lookup("error").Type()
cleanupType = types.NewSignature(nil, nil, nil, false)

View File

@@ -41,6 +41,7 @@ type ProviderSet struct {
Providers []*Provider
Bindings []*IfaceBinding
Values []*Value
Imports []*ProviderSet
}
@@ -100,6 +101,21 @@ type ProviderInput struct {
// TODO(light): Move field name into this struct.
}
// Value describes a value expression.
type Value struct {
// Pos is the source position of the expression defining this value.
Pos token.Pos
// Out is the type this value produces.
Out types.Type
// expr is the expression passed to goose.Value.
expr ast.Expr
// info is the type info for the expression.
info *types.Info
}
// Load finds all the provider sets in the given packages, as well as
// the provider sets' transitive dependencies.
func Load(bctx *build.Context, wd string, pkgs []string) (*Info, error) {
@@ -163,7 +179,7 @@ func (id ProviderSetID) String() string {
// objectCache is a lazily evaluated mapping of objects to goose structures.
type objectCache struct {
prog *loader.Program
objects map[objRef]interface{} // *Provider or *ProviderSet
objects map[objRef]interface{} // *Provider, *ProviderSet, *IfaceBinding, or *Value
}
type objRef struct {
@@ -179,7 +195,8 @@ func newObjectCache(prog *loader.Program) *objectCache {
}
// get converts a Go object into a goose structure. It may return a
// *Provider, a structProviderPair, an *IfaceBinding, or a *ProviderSet.
// *Provider, a structProviderPair, an *IfaceBinding, a *ProviderSet,
// or a *Value.
func (oc *objectCache) get(obj types.Object) (interface{}, error) {
ref := objRef{
importPath: obj.Pkg().Path(),
@@ -239,8 +256,8 @@ func (oc *objectCache) varDecl(obj *types.Var) *ast.ValueSpec {
}
// processExpr converts an expression into a goose structure. It may
// return a *Provider, a structProviderPair, an *IfaceBinding, or a
// *ProviderSet.
// return a *Provider, a structProviderPair, an *IfaceBinding, a
// *ProviderSet, or a *Value.
func (oc *objectCache) processExpr(pkg *loader.PackageInfo, expr ast.Expr) (interface{}, error) {
exprPos := oc.prog.Fset.Position(expr.Pos())
expr = astutil.Unparen(expr)
@@ -269,6 +286,12 @@ func (oc *objectCache) processExpr(pkg *loader.PackageInfo, expr ast.Expr) (inte
return nil, fmt.Errorf("%v: %v", exprPos, err)
}
return b, nil
case "Value":
v, err := processValue(oc.prog.Fset, &pkg.Info, call)
if err != nil {
return nil, fmt.Errorf("%v: %v", exprPos, err)
}
return v, nil
default:
return nil, fmt.Errorf("%v: unknown pattern", exprPos)
}
@@ -312,6 +335,8 @@ func (oc *objectCache) processNewSet(pkg *loader.PackageInfo, call *ast.CallExpr
pset.Bindings = append(pset.Bindings, item)
case structProviderPair:
pset.Providers = append(pset.Providers, item.provider, item.ptrProvider)
case *Value:
pset.Values = append(pset.Values, item)
default:
panic("unknown item type")
}
@@ -471,6 +496,48 @@ func processBind(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*If
}, nil
}
// processValue creates a value from a goose.Value call.
func processValue(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*Value, error) {
// Assumes that call.Fun is goose.Value.
if len(call.Args) != 1 {
return nil, fmt.Errorf("%v: call to Value takes exactly one argument", fset.Position(call.Pos()))
}
ok := true
ast.Inspect(call.Args[0], func(node ast.Node) bool {
switch node.(type) {
case nil, *ast.ArrayType, *ast.BasicLit, *ast.BinaryExpr, *ast.ChanType, *ast.CompositeLit, *ast.FuncType, *ast.Ident, *ast.IndexExpr, *ast.InterfaceType, *ast.KeyValueExpr, *ast.MapType, *ast.ParenExpr, *ast.SelectorExpr, *ast.SliceExpr, *ast.StarExpr, *ast.StructType, *ast.TypeAssertExpr:
// Good!
case *ast.UnaryExpr:
expr := node.(*ast.UnaryExpr)
if expr.Op == token.ARROW {
ok = false
return false
}
case *ast.CallExpr:
// Only acceptable if it's a type conversion.
call := node.(*ast.CallExpr)
if _, isFunc := info.TypeOf(call.Fun).(*types.Signature); isFunc {
ok = false
return false
}
default:
ok = false
return false
}
return true
})
if !ok {
return nil, fmt.Errorf("%v: argument to Value is too complex", fset.Position(call.Pos()))
}
return &Value{
Pos: call.Args[0].Pos(),
Out: info.TypeOf(call.Args[0]),
expr: call.Args[0],
info: info,
}, nil
}
// isInjector checks whether a given function declaration is an
// injector template, returning the goose.Use call. It returns nil if
// the function is not an injector template.

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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 "github.com/google/go-cloud/goose"
var Value = goose.Value(PublicMsg)
var PublicMsg = "Hello, World!"

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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(injectedMessage())
}

View File

@@ -0,0 +1,26 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"bar"
"github.com/google/go-cloud/goose"
)
func injectedMessage() string {
panic(goose.Use(bar.Value))
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,23 @@
// Copyright 2018 Google LLC
//
// 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 (
"os"
"github.com/google/go-cloud/goose"
)
var Value = goose.Value(os.Stdout)

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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.Fprintln(injectedFile(), "Hello, World!")
}

View File

@@ -0,0 +1,28 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"os"
"bar"
"github.com/google/go-cloud/goose"
)
func injectedFile() *os.File {
panic(goose.Use(bar.Value))
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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(injectedMessage())
}

View File

@@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"github.com/google/go-cloud/goose"
)
func injectedMessage() string {
panic(goose.Use(goose.Value("Hello, World!")))
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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 "github.com/google/go-cloud/goose"
var Value = goose.Value(privateMsg)
var privateMsg = "Hello, World!"

View File

@@ -0,0 +1,21 @@
// Copyright 2018 Google LLC
//
// 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(injectedMessage())
}

View File

@@ -0,0 +1,26 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"bar"
"github.com/google/go-cloud/goose"
)
func injectedMessage() string {
panic(goose.Use(bar.Value))
}

View File

@@ -0,0 +1 @@
ERROR

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,36 @@
// Copyright 2018 Google LLC
//
// 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"
"github.com/google/go-cloud/goose"
)
func main() {
fmt.Println(injectFooBar())
}
type Foo int
type FooBar int
var Set = goose.NewSet(
goose.Value(Foo(41)),
provideFooBar)
func provideFooBar(foo Foo) FooBar {
return FooBar(foo) + 1
}

View File

@@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"github.com/google/go-cloud/goose"
)
func injectFooBar() FooBar {
panic(goose.Use(Set))
}

View File

@@ -0,0 +1 @@
42

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,23 @@
// Copyright 2018 Google LLC
//
// 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(injectedMessage())
}
type Foo string

View File

@@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"github.com/google/go-cloud/goose"
)
func injectedMessage() Foo {
panic(goose.Use(goose.Value(Foo("Hello, World!"))))
}

View File

@@ -0,0 +1 @@
Hello, World!

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,26 @@
// Copyright 2018 Google LLC
//
// 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() {
// Value should be deferred until function call.
msg = "Hello, World!"
fmt.Println(injectedMessage())
}
var msg string

View File

@@ -0,0 +1,25 @@
// Copyright 2018 Google LLC
//
// 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 gooseinject
package main
import (
"github.com/google/go-cloud/goose"
)
func injectedMessage() string {
panic(goose.Use(goose.Value(msg)))
}

View File

@@ -0,0 +1 @@
Hello, World!

1
internal/goose/testdata/VarValue/pkg vendored Normal file
View File

@@ -0,0 +1 @@
foo