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>
diff --git a/internal/lsp/source/command.go b/internal/lsp/source/command.go
index 0103ab4..211f562 100644
--- a/internal/lsp/source/command.go
+++ b/internal/lsp/source/command.go
@@ -105,7 +105,10 @@
Name: "extract_variable",
Title: "Extract to variable",
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.
diff --git a/internal/lsp/source/extract.go b/internal/lsp/source/extract.go
index 753a713..f0acf8a 100644
--- a/internal/lsp/source/extract.go
+++ b/internal/lsp/source/extract.go
@@ -22,22 +22,12 @@
)
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 {
- 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)
+ expr, path, ok, err := canExtractVariable(fset, rng, src, file, pkg, info)
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.
var assignment string
@@ -65,7 +55,7 @@
return nil, nil
}
- tok := fset.File(node.Pos())
+ tok := fset.File(expr.Pos())
if tok == nil {
return nil, nil
}
@@ -88,22 +78,23 @@
// canExtractVariable reports whether the code in the given range can be
// extracted to a variable.
-// TODO(rstambler): De-duplicate the logic between extractVariable and
-// canExtractVariable.
-func canExtractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) bool {
+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) {
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)
if len(path) == 0 {
- return false
+ return nil, nil, false, fmt.Errorf("no path enclosing interval")
}
node := path[0]
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)
- return ok
+ expr, ok := node.(ast.Expr)
+ if !ok {
+ return nil, nil, false, fmt.Errorf("node is not an expression")
+ }
+ return expr, path, true, nil
}
// Calculate indentation for insertion.
@@ -415,7 +406,8 @@
hasReturnValues := len(returns)+len(retVars) > 0
if hasReturnValues {
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.