From cbfca74d8aab1cd313cfc183106aabe45e9b5c7a Mon Sep 17 00:00:00 2001 From: shantuo Date: Fri, 17 May 2019 15:56:42 -0700 Subject: [PATCH] wire: support using '-' tag to prevent filling struct fields (#163) --- internal/wire/parse.go | 21 ++++++-- internal/wire/testdata/Struct/foo/foo.go | 2 + .../testdata/StructWithPreventTag/foo/foo.go | 48 +++++++++++++++++++ .../testdata/StructWithPreventTag/foo/wire.go | 26 ++++++++++ .../wire/testdata/StructWithPreventTag/pkg | 1 + .../StructWithPreventTag/want/wire_errs.txt | 1 + .../wire/testdata/UnusedProviders/foo/foo.go | 8 +++- .../wire/testdata/UnusedProviders/foo/wire.go | 7 +-- .../UnusedProviders/want/wire_errs.txt | 10 ++-- 9 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 internal/wire/testdata/StructWithPreventTag/foo/foo.go create mode 100644 internal/wire/testdata/StructWithPreventTag/foo/wire.go create mode 100644 internal/wire/testdata/StructWithPreventTag/pkg create mode 100644 internal/wire/testdata/StructWithPreventTag/want/wire_errs.txt diff --git a/internal/wire/parse.go b/internal/wire/parse.go index cbe5b17..543418a 100644 --- a/internal/wire/parse.go +++ b/internal/wire/parse.go @@ -744,6 +744,8 @@ func funcOutput(sig *types.Signature) (outputSignature, error) { // It produces pointer and non-pointer variants via two values in Out. // // This is a copy of the old processStructProvider, which is deprecated now. +// It will not support any new feature introduced after v0.2. Please use the new +// wire.Struct syntax for those. func processStructLiteralProvider(fset *token.FileSet, typeName *types.TypeName) (*Provider, []error) { out := typeName.Type() st, ok := out.Underlying().(*types.Struct) @@ -813,13 +815,15 @@ func processStructProvider(fset *token.FileSet, info *types.Info, call *ast.Call Out: []types.Type{structPtr.Elem(), structPtr}, } if allFields(call) { - provider.Args = make([]ProviderInput, st.NumFields()) for i := 0; i < st.NumFields(); i++ { + if isPrevented(st, i) { + continue + } f := st.Field(i) - provider.Args[i] = ProviderInput{ + provider.Args = append(provider.Args, ProviderInput{ Type: f.Type(), FieldName: f.Name(), - } + }) } } else { provider.Args = make([]ProviderInput, len(call.Args)-1) @@ -856,6 +860,14 @@ func allFields(call *ast.CallExpr) bool { return strings.EqualFold(strconv.Quote("*"), b.Value) } +// isPrevented checks whether field i is prevented by tag "-". +// Since this is the only tag used by wire, we can do string comparison +// without using reflect. +// TODO(#179): parse the wire tag more robustly. +func isPrevented(st *types.Struct, i int) bool { + return strings.Contains(st.Tag(i), `wire:"-"`) +} + // processBind creates an interface binding from a wire.Bind call. func processBind(fset *token.FileSet, info *types.Info, call *ast.CallExpr) (*IfaceBinding, error) { // Assumes that call.Fun is wire.Bind. @@ -1037,6 +1049,9 @@ func checkField(f ast.Expr, st *types.Struct) (*types.Var, error) { } for i := 0; i < st.NumFields(); i++ { if strings.EqualFold(strconv.Quote(st.Field(i).Name()), b.Value) { + if isPrevented(st, i) { + return nil, fmt.Errorf("%s is prevented from injecting by wire", b.Value) + } return st.Field(i), nil } } diff --git a/internal/wire/testdata/Struct/foo/foo.go b/internal/wire/testdata/Struct/foo/foo.go index 9bb1e52..18d187a 100644 --- a/internal/wire/testdata/Struct/foo/foo.go +++ b/internal/wire/testdata/Struct/foo/foo.go @@ -16,6 +16,7 @@ package main import ( "fmt" + "sync" "github.com/google/wire" ) @@ -31,6 +32,7 @@ type Foo int type Bar int type FooBar struct { + mu sync.Mutex `wire:"-"` Foo Foo Bar Bar } diff --git a/internal/wire/testdata/StructWithPreventTag/foo/foo.go b/internal/wire/testdata/StructWithPreventTag/foo/foo.go new file mode 100644 index 0000000..045f282 --- /dev/null +++ b/internal/wire/testdata/StructWithPreventTag/foo/foo.go @@ -0,0 +1,48 @@ +// 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" + "sync" + + "github.com/google/wire" +) + +func main() { + pfb := injectPartFooBar() + fmt.Println(pfb.Foo) +} + +type Foo int + +type FooBar struct { + mu sync.Mutex `wire:"-"` + Foo Foo +} + +func provideFoo() Foo { + return 42 +} + +func provideMutex() sync.Mutex { + return sync.Mutex{} +} + +var ProhibitSet = wire.NewSet( + wire.Struct(new(FooBar), "mu", "Foo"), + provideMutex, + provideFoo, +) diff --git a/internal/wire/testdata/StructWithPreventTag/foo/wire.go b/internal/wire/testdata/StructWithPreventTag/foo/wire.go new file mode 100644 index 0000000..2f1ee55 --- /dev/null +++ b/internal/wire/testdata/StructWithPreventTag/foo/wire.go @@ -0,0 +1,26 @@ +// 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 injectPartFooBar() FooBar { + wire.Build(ProhibitSet) + return FooBar{} +} diff --git a/internal/wire/testdata/StructWithPreventTag/pkg b/internal/wire/testdata/StructWithPreventTag/pkg new file mode 100644 index 0000000..f7a5c8c --- /dev/null +++ b/internal/wire/testdata/StructWithPreventTag/pkg @@ -0,0 +1 @@ +example.com/foo diff --git a/internal/wire/testdata/StructWithPreventTag/want/wire_errs.txt b/internal/wire/testdata/StructWithPreventTag/want/wire_errs.txt new file mode 100644 index 0000000..2482bc5 --- /dev/null +++ b/internal/wire/testdata/StructWithPreventTag/want/wire_errs.txt @@ -0,0 +1 @@ +example.com/foo/foo.go:x:y: "mu" is prevented from injecting by wire \ No newline at end of file diff --git a/internal/wire/testdata/UnusedProviders/foo/foo.go b/internal/wire/testdata/UnusedProviders/foo/foo.go index 8c7b3d7..f1def3a 100644 --- a/internal/wire/testdata/UnusedProviders/foo/foo.go +++ b/internal/wire/testdata/UnusedProviders/foo/foo.go @@ -21,7 +21,7 @@ import ( ) func main() { - fmt.Println(injectBar()) + fmt.Println(injectFooBar()) } type Foo int @@ -31,6 +31,12 @@ type UnusedInSet int type OneOfTwo int type TwoOfTwo int +type FooBar struct { + MyFoo *Foo + MyBar Bar + MyUnused Unused +} + var ( unusedSet = wire.NewSet(provideUnusedInSet) partiallyUsedSet = wire.NewSet(provideOneOfTwo, provideTwoOfTwo) diff --git a/internal/wire/testdata/UnusedProviders/foo/wire.go b/internal/wire/testdata/UnusedProviders/foo/wire.go index 779207d..62bebd8 100644 --- a/internal/wire/testdata/UnusedProviders/foo/wire.go +++ b/internal/wire/testdata/UnusedProviders/foo/wire.go @@ -20,16 +20,17 @@ import ( "github.com/google/wire" ) -func injectBar() Bar { +func injectFooBar() FooBar { wire.Build( provideFoo, // needed as input for provideBar - provideBar, // needed for Bar + provideBar, // needed for FooBar partiallyUsedSet, // 1/2 providers in the set are needed provideUnused, // not needed -> error wire.Value("unused"), // not needed -> error unusedSet, // nothing in set is needed -> error wire.Bind(new(Fooer), new(*Foo)), // binding to Fooer is not needed -> error wire.FieldsOf(new(S), "Cfg"), // S.Cfg not needed -> error + wire.Struct(new(FooBar), "MyFoo", "MyBar"), // needed for FooBar ) - return 0 + return FooBar{} } diff --git a/internal/wire/testdata/UnusedProviders/want/wire_errs.txt b/internal/wire/testdata/UnusedProviders/want/wire_errs.txt index a34cab2..54dd582 100644 --- a/internal/wire/testdata/UnusedProviders/want/wire_errs.txt +++ b/internal/wire/testdata/UnusedProviders/want/wire_errs.txt @@ -1,9 +1,9 @@ -example.com/foo/wire.go:x:y: inject injectBar: unused provider set "unusedSet" +example.com/foo/wire.go:x:y: inject injectFooBar: unused provider set "unusedSet" -example.com/foo/wire.go:x:y: inject injectBar: unused provider "main.provideUnused" +example.com/foo/wire.go:x:y: inject injectFooBar: unused provider "main.provideUnused" -example.com/foo/wire.go:x:y: inject injectBar: unused value of type string +example.com/foo/wire.go:x:y: inject injectFooBar: 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 injectFooBar: 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 \ No newline at end of file +example.com/foo/wire.go:x:y: inject injectFooBar: unused field "example.com/foo.S".Cfg \ No newline at end of file