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

@@ -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,50 +119,69 @@ 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))
}
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
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 {
return err
}
index.Set(typ, index.At(p.Out))
return nil
}
index.Set(typ, index.At(p.Out))
return nil
}
for _, a := range p.Args {
// TODO(light): This will discard grown trail arrays.
if err := visit(append(trail, a)); err != nil {
return err
for _, a := range p.Args {
// TODO(light): This will discard grown trail arrays.
if err := visit(append(trail, a)); err != nil {
return err
}
}
}
args := make([]int, len(p.Args))
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 := make([]int, len(p.Args))
ins := make([]types.Type, len(p.Args))
for i := range p.Args {
ins[i] = p.Args[i].Type
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,
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")
}
index.Set(typ, len(given)+len(calls))
calls = append(calls, call{
importPath: p.ImportPath,
name: p.Name,
args: args,
isStruct: p.IsStruct,
fieldNames: p.Fields,
ins: ins,
out: typ,
hasCleanup: p.HasCleanup,
hasErr: p.HasErr,
})
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,15 +244,24 @@ 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 {
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)
switch c.kind {
case funcProviderCall:
g.qualifyImport(c.importPath)
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)
@@ -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