goose: refactor *gen.inject
The function had grown too long. Several related cleanups: - Factored out the function return value logic, which had been duplicated between providers and injectors. - Moved code generation for different provider call types into separate functions. This moves injector-specific state to a new type injectorGen to keep the parameter count down. - Since it's infeasible to keep the "shadow pass" collecting import identifiers in sync the spread out logic, the injector code generation is just run twice, with initial output discarded. - Removed the zero value logic left over from Optional. Reviewed-by: Tuo Shan <shantuo@google.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package goose
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
@@ -384,43 +385,20 @@ func qualifiedIdentObject(info *types.Info, expr ast.Expr) types.Object {
|
||||
// processFuncProvider creates a provider for a function declaration.
|
||||
func processFuncProvider(fset *token.FileSet, fn *types.Func) (*Provider, error) {
|
||||
sig := fn.Type().(*types.Signature)
|
||||
|
||||
fpos := fn.Pos()
|
||||
r := sig.Results()
|
||||
var hasCleanup, hasErr bool
|
||||
switch r.Len() {
|
||||
case 1:
|
||||
hasCleanup, hasErr = false, false
|
||||
case 2:
|
||||
switch t := r.At(1).Type(); {
|
||||
case types.Identical(t, errorType):
|
||||
hasCleanup, hasErr = false, true
|
||||
case types.Identical(t, cleanupType):
|
||||
hasCleanup, hasErr = true, false
|
||||
default:
|
||||
return nil, fmt.Errorf("%v: wrong signature for provider %s: second return type must be error or func()", fset.Position(fpos), fn.Name())
|
||||
}
|
||||
case 3:
|
||||
if t := r.At(1).Type(); !types.Identical(t, cleanupType) {
|
||||
return nil, fmt.Errorf("%v: wrong signature for provider %s: second return type must be func()", fset.Position(fpos), fn.Name())
|
||||
}
|
||||
if t := r.At(2).Type(); !types.Identical(t, errorType) {
|
||||
return nil, fmt.Errorf("%v: wrong signature for provider %s: third return type must be error", fset.Position(fpos), fn.Name())
|
||||
}
|
||||
hasCleanup, hasErr = true, true
|
||||
default:
|
||||
return nil, fmt.Errorf("%v: wrong signature for provider %s: must have one return value and optional error", fset.Position(fpos), fn.Name())
|
||||
providerSig, err := funcOutput(sig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: wrong signature for provider %s: %v", fset.Position(fpos), fn.Name(), err)
|
||||
}
|
||||
out := r.At(0).Type()
|
||||
params := sig.Params()
|
||||
provider := &Provider{
|
||||
ImportPath: fn.Pkg().Path(),
|
||||
Name: fn.Name(),
|
||||
Pos: fn.Pos(),
|
||||
Args: make([]ProviderInput, params.Len()),
|
||||
Out: out,
|
||||
HasCleanup: hasCleanup,
|
||||
HasErr: hasErr,
|
||||
Out: providerSig.out,
|
||||
HasCleanup: providerSig.cleanup,
|
||||
HasErr: providerSig.err,
|
||||
}
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
provider.Args[i] = ProviderInput{
|
||||
@@ -435,6 +413,47 @@ func processFuncProvider(fset *token.FileSet, fn *types.Func) (*Provider, error)
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
type outputSignature struct {
|
||||
out types.Type
|
||||
cleanup bool
|
||||
err bool
|
||||
}
|
||||
|
||||
// funcOutput validates an injector or provider function's return signature.
|
||||
func funcOutput(sig *types.Signature) (outputSignature, error) {
|
||||
results := sig.Results()
|
||||
switch results.Len() {
|
||||
case 0:
|
||||
return outputSignature{}, errors.New("no return values")
|
||||
case 1:
|
||||
return outputSignature{out: results.At(0).Type()}, nil
|
||||
case 2:
|
||||
out := results.At(0).Type()
|
||||
switch t := results.At(1).Type(); {
|
||||
case types.Identical(t, errorType):
|
||||
return outputSignature{out: out, err: true}, nil
|
||||
case types.Identical(t, cleanupType):
|
||||
return outputSignature{out: out, cleanup: true}, nil
|
||||
default:
|
||||
return outputSignature{}, fmt.Errorf("second return type is %s; must be error or func()", types.TypeString(t, nil))
|
||||
}
|
||||
case 3:
|
||||
if t := results.At(1).Type(); !types.Identical(t, cleanupType) {
|
||||
return outputSignature{}, fmt.Errorf("second return type is %s; must be func()", types.TypeString(t, nil))
|
||||
}
|
||||
if t := results.At(2).Type(); !types.Identical(t, errorType) {
|
||||
return outputSignature{}, fmt.Errorf("third return type is %s; must be error", types.TypeString(t, nil))
|
||||
}
|
||||
return outputSignature{
|
||||
out: results.At(0).Type(),
|
||||
cleanup: true,
|
||||
err: true,
|
||||
}, nil
|
||||
default:
|
||||
return outputSignature{}, errors.New("too many return values")
|
||||
}
|
||||
}
|
||||
|
||||
// processStructProvider creates a provider for a named struct type.
|
||||
// It only produces the non-pointer variant.
|
||||
func processStructProvider(fset *token.FileSet, typeName *types.TypeName) (*Provider, error) {
|
||||
|
||||
Reference in New Issue
Block a user