1
0
mirror of https://github.com/golang/go synced 2024-09-30 16:08:36 -06:00

internal/lsp: de-duplicate logic for canExtractVariable

We'd like to call canExtractVariable in extractVariable without
duplicating logic. The same needs to be done for canExtractFunction.

Change-Id: Ia99befabbafffcf13dd3bc12355f9ddb81a71002
Reviewed-on: https://go-review.googlesource.com/c/tools/+/245135
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Josh Baum <joshbaum@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Rebecca Stambler 2020-07-28 12:00:17 -04:00
parent 342ee1054f
commit edd3c8e9e2
2 changed files with 20 additions and 25 deletions

View File

@ -105,7 +105,10 @@ var (
Name: "extract_variable", Name: "extract_variable",
Title: "Extract to variable", Title: "Extract to variable",
suggestedFixFn: extractVariable, suggestedFixFn: extractVariable,
appliesFn: canExtractVariable, appliesFn: func(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) bool {
_, _, ok, _ := canExtractVariable(fset, rng, src, file, pkg, info)
return ok
},
} }
// CommandExtractFunction extracts statements to a function. // CommandExtractFunction extracts statements to a function.

View File

@ -22,22 +22,12 @@ import (
) )
func extractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) { func extractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error) {
if rng.Start == rng.End { expr, path, ok, err := canExtractVariable(fset, rng, src, file, pkg, info)
return nil, fmt.Errorf("extractVariable: start and end are equal (%v)", fset.Position(rng.Start))
}
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.End)
if len(path) == 0 {
return nil, fmt.Errorf("extractVariable: no path enclosing interval")
}
node := path[0]
if rng.Start != node.Pos() || rng.End != node.End() {
return nil, fmt.Errorf("extractVariable: node doesn't perfectly enclose range")
}
expr, ok := node.(ast.Expr)
if !ok { if !ok {
return nil, fmt.Errorf("extractVariable: node is not an expression") return nil, fmt.Errorf("extractVariable: cannot extract %s: %v", fset.Position(rng.Start), err)
} }
name := generateAvailableIdentifier(node.Pos(), file, path, info, "x", 0)
name := generateAvailableIdentifier(expr.Pos(), file, path, info, "x", 0)
// Create new AST node for extracted code. // Create new AST node for extracted code.
var assignment string var assignment string
@ -65,7 +55,7 @@ func extractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.
return nil, nil return nil, nil
} }
tok := fset.File(node.Pos()) tok := fset.File(expr.Pos())
if tok == nil { if tok == nil {
return nil, nil return nil, nil
} }
@ -88,22 +78,23 @@ func extractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.
// canExtractVariable reports whether the code in the given range can be // canExtractVariable reports whether the code in the given range can be
// extracted to a variable. // extracted to a variable.
// TODO(rstambler): De-duplicate the logic between extractVariable and func canExtractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (ast.Expr, []ast.Node, bool, error) {
// canExtractVariable.
func canExtractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) bool {
if rng.Start == rng.End { if rng.Start == rng.End {
return false return nil, nil, false, fmt.Errorf("start and end are equal")
} }
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.End) path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.End)
if len(path) == 0 { if len(path) == 0 {
return false return nil, nil, false, fmt.Errorf("no path enclosing interval")
} }
node := path[0] node := path[0]
if rng.Start != node.Pos() || rng.End != node.End() { if rng.Start != node.Pos() || rng.End != node.End() {
return false return nil, nil, false, fmt.Errorf("range does not map to an AST node")
} }
_, ok := node.(ast.Expr) expr, ok := node.(ast.Expr)
return ok if !ok {
return nil, nil, false, fmt.Errorf("node is not an expression")
}
return expr, path, true, nil
} }
// Calculate indentation for insertion. // Calculate indentation for insertion.
@ -415,7 +406,8 @@ func extractFunction(fset *token.FileSet, rng span.Range, src []byte, file *ast.
hasReturnValues := len(returns)+len(retVars) > 0 hasReturnValues := len(returns)+len(retVars) > 0
if hasReturnValues { if hasReturnValues {
extractedBlock.List = append(extractedBlock.List, &ast.ReturnStmt{ extractedBlock.List = append(extractedBlock.List, &ast.ReturnStmt{
Results: append(returns, getZeroVals(retVars)...)}) Results: append(returns, getZeroVals(retVars)...),
})
} }
// Construct the appropriate call to the extracted function. // Construct the appropriate call to the extracted function.