golang.org/x/tools/gopls@v0.15.3/internal/golang/extract.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package golang
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/ast"
    11  	"go/format"
    12  	"go/parser"
    13  	"go/token"
    14  	"go/types"
    15  	"sort"
    16  	"strings"
    17  	"text/scanner"
    18  
    19  	"golang.org/x/tools/go/analysis"
    20  	"golang.org/x/tools/go/ast/astutil"
    21  	"golang.org/x/tools/gopls/internal/util/bug"
    22  	"golang.org/x/tools/gopls/internal/util/safetoken"
    23  	"golang.org/x/tools/internal/analysisinternal"
    24  )
    25  
    26  func extractVariable(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
    27  	tokFile := fset.File(file.Pos())
    28  	expr, path, ok, err := CanExtractVariable(start, end, file)
    29  	if !ok {
    30  		return nil, nil, fmt.Errorf("extractVariable: cannot extract %s: %v", safetoken.StartPosition(fset, start), err)
    31  	}
    32  
    33  	// Create new AST node for extracted code.
    34  	var lhsNames []string
    35  	switch expr := expr.(type) {
    36  	// TODO: stricter rules for selectorExpr.
    37  	case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.SliceExpr,
    38  		*ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr:
    39  		lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", 0)
    40  		lhsNames = append(lhsNames, lhsName)
    41  	case *ast.CallExpr:
    42  		tup, ok := info.TypeOf(expr).(*types.Tuple)
    43  		if !ok {
    44  			// If the call expression only has one return value, we can treat it the
    45  			// same as our standard extract variable case.
    46  			lhsName, _ := generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", 0)
    47  			lhsNames = append(lhsNames, lhsName)
    48  			break
    49  		}
    50  		idx := 0
    51  		for i := 0; i < tup.Len(); i++ {
    52  			// Generate a unique variable for each return value.
    53  			var lhsName string
    54  			lhsName, idx = generateAvailableIdentifier(expr.Pos(), path, pkg, info, "x", idx)
    55  			lhsNames = append(lhsNames, lhsName)
    56  		}
    57  	default:
    58  		return nil, nil, fmt.Errorf("cannot extract %T", expr)
    59  	}
    60  
    61  	insertBeforeStmt := analysisinternal.StmtToInsertVarBefore(path)
    62  	if insertBeforeStmt == nil {
    63  		return nil, nil, fmt.Errorf("cannot find location to insert extraction")
    64  	}
    65  	indent, err := calculateIndentation(src, tokFile, insertBeforeStmt)
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  	newLineIndent := "\n" + indent
    70  
    71  	lhs := strings.Join(lhsNames, ", ")
    72  	assignStmt := &ast.AssignStmt{
    73  		Lhs: []ast.Expr{ast.NewIdent(lhs)},
    74  		Tok: token.DEFINE,
    75  		Rhs: []ast.Expr{expr},
    76  	}
    77  	var buf bytes.Buffer
    78  	if err := format.Node(&buf, fset, assignStmt); err != nil {
    79  		return nil, nil, err
    80  	}
    81  	assignment := strings.ReplaceAll(buf.String(), "\n", newLineIndent) + newLineIndent
    82  
    83  	return fset, &analysis.SuggestedFix{
    84  		TextEdits: []analysis.TextEdit{
    85  			{
    86  				Pos:     insertBeforeStmt.Pos(),
    87  				End:     insertBeforeStmt.Pos(),
    88  				NewText: []byte(assignment),
    89  			},
    90  			{
    91  				Pos:     start,
    92  				End:     end,
    93  				NewText: []byte(lhs),
    94  			},
    95  		},
    96  	}, nil
    97  }
    98  
    99  // CanExtractVariable reports whether the code in the given range can be
   100  // extracted to a variable.
   101  func CanExtractVariable(start, end token.Pos, file *ast.File) (ast.Expr, []ast.Node, bool, error) {
   102  	if start == end {
   103  		return nil, nil, false, fmt.Errorf("start and end are equal")
   104  	}
   105  	path, _ := astutil.PathEnclosingInterval(file, start, end)
   106  	if len(path) == 0 {
   107  		return nil, nil, false, fmt.Errorf("no path enclosing interval")
   108  	}
   109  	for _, n := range path {
   110  		if _, ok := n.(*ast.ImportSpec); ok {
   111  			return nil, nil, false, fmt.Errorf("cannot extract variable in an import block")
   112  		}
   113  	}
   114  	node := path[0]
   115  	if start != node.Pos() || end != node.End() {
   116  		return nil, nil, false, fmt.Errorf("range does not map to an AST node")
   117  	}
   118  	expr, ok := node.(ast.Expr)
   119  	if !ok {
   120  		return nil, nil, false, fmt.Errorf("node is not an expression")
   121  	}
   122  	switch expr.(type) {
   123  	case *ast.BasicLit, *ast.CompositeLit, *ast.IndexExpr, *ast.CallExpr,
   124  		*ast.SliceExpr, *ast.UnaryExpr, *ast.BinaryExpr, *ast.SelectorExpr:
   125  		return expr, path, true, nil
   126  	}
   127  	return nil, nil, false, fmt.Errorf("cannot extract an %T to a variable", expr)
   128  }
   129  
   130  // Calculate indentation for insertion.
   131  // When inserting lines of code, we must ensure that the lines have consistent
   132  // formatting (i.e. the proper indentation). To do so, we observe the indentation on the
   133  // line of code on which the insertion occurs.
   134  func calculateIndentation(content []byte, tok *token.File, insertBeforeStmt ast.Node) (string, error) {
   135  	line := safetoken.Line(tok, insertBeforeStmt.Pos())
   136  	lineOffset, stmtOffset, err := safetoken.Offsets(tok, tok.LineStart(line), insertBeforeStmt.Pos())
   137  	if err != nil {
   138  		return "", err
   139  	}
   140  	return string(content[lineOffset:stmtOffset]), nil
   141  }
   142  
   143  // generateAvailableIdentifier adjusts the new function name until there are no collisions in scope.
   144  // Possible collisions include other function and variable names. Returns the next index to check for prefix.
   145  func generateAvailableIdentifier(pos token.Pos, path []ast.Node, pkg *types.Package, info *types.Info, prefix string, idx int) (string, int) {
   146  	scopes := CollectScopes(info, path, pos)
   147  	scopes = append(scopes, pkg.Scope())
   148  	return generateIdentifier(idx, prefix, func(name string) bool {
   149  		for _, scope := range scopes {
   150  			if scope != nil && scope.Lookup(name) != nil {
   151  				return true
   152  			}
   153  		}
   154  		return false
   155  	})
   156  }
   157  
   158  func generateIdentifier(idx int, prefix string, hasCollision func(string) bool) (string, int) {
   159  	name := prefix
   160  	if idx != 0 {
   161  		name += fmt.Sprintf("%d", idx)
   162  	}
   163  	for hasCollision(name) {
   164  		idx++
   165  		name = fmt.Sprintf("%v%d", prefix, idx)
   166  	}
   167  	return name, idx + 1
   168  }
   169  
   170  // returnVariable keeps track of the information we need to properly introduce a new variable
   171  // that we will return in the extracted function.
   172  type returnVariable struct {
   173  	// name is the identifier that is used on the left-hand side of the call to
   174  	// the extracted function.
   175  	name ast.Expr
   176  	// decl is the declaration of the variable. It is used in the type signature of the
   177  	// extracted function and for variable declarations.
   178  	decl *ast.Field
   179  	// zeroVal is the "zero value" of the type of the variable. It is used in a return
   180  	// statement in the extracted function.
   181  	zeroVal ast.Expr
   182  }
   183  
   184  // extractMethod refactors the selected block of code into a new method.
   185  func extractMethod(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
   186  	return extractFunctionMethod(fset, start, end, src, file, pkg, info, true)
   187  }
   188  
   189  // extractFunction refactors the selected block of code into a new function.
   190  func extractFunction(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*token.FileSet, *analysis.SuggestedFix, error) {
   191  	return extractFunctionMethod(fset, start, end, src, file, pkg, info, false)
   192  }
   193  
   194  // extractFunctionMethod refactors the selected block of code into a new function/method.
   195  // It also replaces the selected block of code with a call to the extracted
   196  // function. First, we manually adjust the selection range. We remove trailing
   197  // and leading whitespace characters to ensure the range is precisely bounded
   198  // by AST nodes. Next, we determine the variables that will be the parameters
   199  // and return values of the extracted function/method. Lastly, we construct the call
   200  // of the function/method and insert this call as well as the extracted function/method into
   201  // their proper locations.
   202  func extractFunctionMethod(fset *token.FileSet, start, end token.Pos, src []byte, file *ast.File, pkg *types.Package, info *types.Info, isMethod bool) (*token.FileSet, *analysis.SuggestedFix, error) {
   203  	errorPrefix := "extractFunction"
   204  	if isMethod {
   205  		errorPrefix = "extractMethod"
   206  	}
   207  
   208  	tok := fset.File(file.Pos())
   209  	if tok == nil {
   210  		return nil, nil, bug.Errorf("no file for position")
   211  	}
   212  	p, ok, methodOk, err := CanExtractFunction(tok, start, end, src, file)
   213  	if (!ok && !isMethod) || (!methodOk && isMethod) {
   214  		return nil, nil, fmt.Errorf("%s: cannot extract %s: %v", errorPrefix,
   215  			safetoken.StartPosition(fset, start), err)
   216  	}
   217  	tok, path, start, end, outer, node := p.tok, p.path, p.start, p.end, p.outer, p.node
   218  	fileScope := info.Scopes[file]
   219  	if fileScope == nil {
   220  		return nil, nil, fmt.Errorf("%s: file scope is empty", errorPrefix)
   221  	}
   222  	pkgScope := fileScope.Parent()
   223  	if pkgScope == nil {
   224  		return nil, nil, fmt.Errorf("%s: package scope is empty", errorPrefix)
   225  	}
   226  
   227  	// A return statement is non-nested if its parent node is equal to the parent node
   228  	// of the first node in the selection. These cases must be handled separately because
   229  	// non-nested return statements are guaranteed to execute.
   230  	var retStmts []*ast.ReturnStmt
   231  	var hasNonNestedReturn bool
   232  	startParent := findParent(outer, node)
   233  	ast.Inspect(outer, func(n ast.Node) bool {
   234  		if n == nil {
   235  			return false
   236  		}
   237  		if n.Pos() < start || n.End() > end {
   238  			return n.Pos() <= end
   239  		}
   240  		ret, ok := n.(*ast.ReturnStmt)
   241  		if !ok {
   242  			return true
   243  		}
   244  		if findParent(outer, n) == startParent {
   245  			hasNonNestedReturn = true
   246  		}
   247  		retStmts = append(retStmts, ret)
   248  		return false
   249  	})
   250  	containsReturnStatement := len(retStmts) > 0
   251  
   252  	// Now that we have determined the correct range for the selection block,
   253  	// we must determine the signature of the extracted function. We will then replace
   254  	// the block with an assignment statement that calls the extracted function with
   255  	// the appropriate parameters and return values.
   256  	variables, err := collectFreeVars(info, file, fileScope, pkgScope, start, end, path[0])
   257  	if err != nil {
   258  		return nil, nil, err
   259  	}
   260  
   261  	var (
   262  		receiverUsed bool
   263  		receiver     *ast.Field
   264  		receiverName string
   265  		receiverObj  types.Object
   266  	)
   267  	if isMethod {
   268  		if outer == nil || outer.Recv == nil || len(outer.Recv.List) == 0 {
   269  			return nil, nil, fmt.Errorf("%s: cannot extract need method receiver", errorPrefix)
   270  		}
   271  		receiver = outer.Recv.List[0]
   272  		if len(receiver.Names) == 0 || receiver.Names[0] == nil {
   273  			return nil, nil, fmt.Errorf("%s: cannot extract need method receiver name", errorPrefix)
   274  		}
   275  		recvName := receiver.Names[0]
   276  		receiverName = recvName.Name
   277  		receiverObj = info.ObjectOf(recvName)
   278  	}
   279  
   280  	var (
   281  		params, returns         []ast.Expr     // used when calling the extracted function
   282  		paramTypes, returnTypes []*ast.Field   // used in the signature of the extracted function
   283  		uninitialized           []types.Object // vars we will need to initialize before the call
   284  	)
   285  
   286  	// Avoid duplicates while traversing vars and uninitialized.
   287  	seenVars := make(map[types.Object]ast.Expr)
   288  	seenUninitialized := make(map[types.Object]struct{})
   289  
   290  	// Some variables on the left-hand side of our assignment statement may be free. If our
   291  	// selection begins in the same scope in which the free variable is defined, we can
   292  	// redefine it in our assignment statement. See the following example, where 'b' and
   293  	// 'err' (both free variables) can be redefined in the second funcCall() while maintaining
   294  	// correctness.
   295  	//
   296  	//
   297  	// Not Redefined:
   298  	//
   299  	// a, err := funcCall()
   300  	// var b int
   301  	// b, err = funcCall()
   302  	//
   303  	// Redefined:
   304  	//
   305  	// a, err := funcCall()
   306  	// b, err := funcCall()
   307  	//
   308  	// We track the number of free variables that can be redefined to maintain our preference
   309  	// of using "x, y, z := fn()" style assignment statements.
   310  	var canRedefineCount int
   311  
   312  	// Each identifier in the selected block must become (1) a parameter to the
   313  	// extracted function, (2) a return value of the extracted function, or (3) a local
   314  	// variable in the extracted function. Determine the outcome(s) for each variable
   315  	// based on whether it is free, altered within the selected block, and used outside
   316  	// of the selected block.
   317  	for _, v := range variables {
   318  		if _, ok := seenVars[v.obj]; ok {
   319  			continue
   320  		}
   321  		if v.obj.Name() == "_" {
   322  			// The blank identifier is always a local variable
   323  			continue
   324  		}
   325  		typ := analysisinternal.TypeExpr(file, pkg, v.obj.Type())
   326  		if typ == nil {
   327  			return nil, nil, fmt.Errorf("nil AST expression for type: %v", v.obj.Name())
   328  		}
   329  		seenVars[v.obj] = typ
   330  		identifier := ast.NewIdent(v.obj.Name())
   331  		// An identifier must meet three conditions to become a return value of the
   332  		// extracted function. (1) its value must be defined or reassigned within
   333  		// the selection (isAssigned), (2) it must be used at least once after the
   334  		// selection (isUsed), and (3) its first use after the selection
   335  		// cannot be its own reassignment or redefinition (objOverriden).
   336  		vscope := v.obj.Parent()
   337  		if vscope == nil {
   338  			return nil, nil, fmt.Errorf("parent nil")
   339  		}
   340  		isUsed, firstUseAfter := objUsed(info, end, vscope.End(), v.obj)
   341  		if v.assigned && isUsed && !varOverridden(info, firstUseAfter, v.obj, v.free, outer) {
   342  			returnTypes = append(returnTypes, &ast.Field{Type: typ})
   343  			returns = append(returns, identifier)
   344  			if !v.free {
   345  				uninitialized = append(uninitialized, v.obj)
   346  
   347  			} else {
   348  				// In go1.22, Scope.Pos for function scopes changed (#60752):
   349  				// it used to start at the body ('{'), now it starts at "func".
   350  				//
   351  				// The second condition below handles the case when
   352  				// v's block is the FuncDecl.Body itself.
   353  				if vscope.Pos() == startParent.Pos() ||
   354  					startParent == outer.Body && vscope == info.Scopes[outer.Type] {
   355  					canRedefineCount++
   356  				}
   357  			}
   358  		}
   359  		// An identifier must meet two conditions to become a parameter of the
   360  		// extracted function. (1) it must be free (isFree), and (2) its first
   361  		// use within the selection cannot be its own definition (isDefined).
   362  		if v.free && !v.defined {
   363  			// Skip the selector for a method.
   364  			if isMethod && v.obj == receiverObj {
   365  				receiverUsed = true
   366  				continue
   367  			}
   368  			params = append(params, identifier)
   369  			paramTypes = append(paramTypes, &ast.Field{
   370  				Names: []*ast.Ident{identifier},
   371  				Type:  typ,
   372  			})
   373  		}
   374  	}
   375  
   376  	reorderParams(params, paramTypes)
   377  
   378  	// Find the function literal that encloses the selection. The enclosing function literal
   379  	// may not be the enclosing function declaration (i.e. 'outer'). For example, in the
   380  	// following block:
   381  	//
   382  	// func main() {
   383  	//     ast.Inspect(node, func(n ast.Node) bool {
   384  	//         v := 1 // this line extracted
   385  	//         return true
   386  	//     })
   387  	// }
   388  	//
   389  	// 'outer' is main(). However, the extracted selection most directly belongs to
   390  	// the anonymous function literal, the second argument of ast.Inspect(). We use the
   391  	// enclosing function literal to determine the proper return types for return statements
   392  	// within the selection. We still need the enclosing function declaration because this is
   393  	// the top-level declaration. We inspect the top-level declaration to look for variables
   394  	// as well as for code replacement.
   395  	enclosing := outer.Type
   396  	for _, p := range path {
   397  		if p == enclosing {
   398  			break
   399  		}
   400  		if fl, ok := p.(*ast.FuncLit); ok {
   401  			enclosing = fl.Type
   402  			break
   403  		}
   404  	}
   405  
   406  	// We put the selection in a constructed file. We can then traverse and edit
   407  	// the extracted selection without modifying the original AST.
   408  	startOffset, endOffset, err := safetoken.Offsets(tok, start, end)
   409  	if err != nil {
   410  		return nil, nil, err
   411  	}
   412  	selection := src[startOffset:endOffset]
   413  	extractedBlock, err := parseBlockStmt(fset, selection)
   414  	if err != nil {
   415  		return nil, nil, err
   416  	}
   417  
   418  	// We need to account for return statements in the selected block, as they will complicate
   419  	// the logical flow of the extracted function. See the following example, where ** denotes
   420  	// the range to be extracted.
   421  	//
   422  	// Before:
   423  	//
   424  	// func _() int {
   425  	//     a := 1
   426  	//     b := 2
   427  	//     **if a == b {
   428  	//         return a
   429  	//     }**
   430  	//     ...
   431  	// }
   432  	//
   433  	// After:
   434  	//
   435  	// func _() int {
   436  	//     a := 1
   437  	//     b := 2
   438  	//     cond0, ret0 := x0(a, b)
   439  	//     if cond0 {
   440  	//         return ret0
   441  	//     }
   442  	//     ...
   443  	// }
   444  	//
   445  	// func x0(a int, b int) (bool, int) {
   446  	//     if a == b {
   447  	//         return true, a
   448  	//     }
   449  	//     return false, 0
   450  	// }
   451  	//
   452  	// We handle returns by adding an additional boolean return value to the extracted function.
   453  	// This bool reports whether the original function would have returned. Because the
   454  	// extracted selection contains a return statement, we must also add the types in the
   455  	// return signature of the enclosing function to the return signature of the
   456  	// extracted function. We then add an extra if statement checking this boolean value
   457  	// in the original function. If the condition is met, the original function should
   458  	// return a value, mimicking the functionality of the original return statement(s)
   459  	// in the selection.
   460  	//
   461  	// If there is a return that is guaranteed to execute (hasNonNestedReturns=true), then
   462  	// we don't need to include this additional condition check and can simply return.
   463  	//
   464  	// Before:
   465  	//
   466  	// func _() int {
   467  	//     a := 1
   468  	//     b := 2
   469  	//     **if a == b {
   470  	//         return a
   471  	//     }
   472  	//	   return b**
   473  	// }
   474  	//
   475  	// After:
   476  	//
   477  	// func _() int {
   478  	//     a := 1
   479  	//     b := 2
   480  	//     return x0(a, b)
   481  	// }
   482  	//
   483  	// func x0(a int, b int) int {
   484  	//     if a == b {
   485  	//         return a
   486  	//     }
   487  	//     return b
   488  	// }
   489  
   490  	var retVars []*returnVariable
   491  	var ifReturn *ast.IfStmt
   492  	if containsReturnStatement {
   493  		if !hasNonNestedReturn {
   494  			// The selected block contained return statements, so we have to modify the
   495  			// signature of the extracted function as described above. Adjust all of
   496  			// the return statements in the extracted function to reflect this change in
   497  			// signature.
   498  			if err := adjustReturnStatements(returnTypes, seenVars, file, pkg, extractedBlock); err != nil {
   499  				return nil, nil, err
   500  			}
   501  		}
   502  		// Collect the additional return values and types needed to accommodate return
   503  		// statements in the selection. Update the type signature of the extracted
   504  		// function and construct the if statement that will be inserted in the enclosing
   505  		// function.
   506  		retVars, ifReturn, err = generateReturnInfo(enclosing, pkg, path, file, info, start, hasNonNestedReturn)
   507  		if err != nil {
   508  			return nil, nil, err
   509  		}
   510  	}
   511  
   512  	// Add a return statement to the end of the new function. This return statement must include
   513  	// the values for the types of the original extracted function signature and (if a return
   514  	// statement is present in the selection) enclosing function signature.
   515  	// This only needs to be done if the selections does not have a non-nested return, otherwise
   516  	// it already terminates with a return statement.
   517  	hasReturnValues := len(returns)+len(retVars) > 0
   518  	if hasReturnValues && !hasNonNestedReturn {
   519  		extractedBlock.List = append(extractedBlock.List, &ast.ReturnStmt{
   520  			Results: append(returns, getZeroVals(retVars)...),
   521  		})
   522  	}
   523  
   524  	// Construct the appropriate call to the extracted function.
   525  	// We must meet two conditions to use ":=" instead of '='. (1) there must be at least
   526  	// one variable on the lhs that is uninitialized (non-free) prior to the assignment.
   527  	// (2) all of the initialized (free) variables on the lhs must be able to be redefined.
   528  	sym := token.ASSIGN
   529  	canDefineCount := len(uninitialized) + canRedefineCount
   530  	canDefine := len(uninitialized)+len(retVars) > 0 && canDefineCount == len(returns)
   531  	if canDefine {
   532  		sym = token.DEFINE
   533  	}
   534  	var name, funName string
   535  	if isMethod {
   536  		name = "newMethod"
   537  		// TODO(suzmue): generate a name that does not conflict for "newMethod".
   538  		funName = name
   539  	} else {
   540  		name = "newFunction"
   541  		funName, _ = generateAvailableIdentifier(start, path, pkg, info, name, 0)
   542  	}
   543  	extractedFunCall := generateFuncCall(hasNonNestedReturn, hasReturnValues, params,
   544  		append(returns, getNames(retVars)...), funName, sym, receiverName)
   545  
   546  	// Build the extracted function.
   547  	newFunc := &ast.FuncDecl{
   548  		Name: ast.NewIdent(funName),
   549  		Type: &ast.FuncType{
   550  			Params:  &ast.FieldList{List: paramTypes},
   551  			Results: &ast.FieldList{List: append(returnTypes, getDecls(retVars)...)},
   552  		},
   553  		Body: extractedBlock,
   554  	}
   555  	if isMethod {
   556  		var names []*ast.Ident
   557  		if receiverUsed {
   558  			names = append(names, ast.NewIdent(receiverName))
   559  		}
   560  		newFunc.Recv = &ast.FieldList{
   561  			List: []*ast.Field{{
   562  				Names: names,
   563  				Type:  receiver.Type,
   564  			}},
   565  		}
   566  	}
   567  
   568  	// Create variable declarations for any identifiers that need to be initialized prior to
   569  	// calling the extracted function. We do not manually initialize variables if every return
   570  	// value is uninitialized. We can use := to initialize the variables in this situation.
   571  	var declarations []ast.Stmt
   572  	if canDefineCount != len(returns) {
   573  		declarations = initializeVars(uninitialized, retVars, seenUninitialized, seenVars)
   574  	}
   575  
   576  	var declBuf, replaceBuf, newFuncBuf, ifBuf, commentBuf bytes.Buffer
   577  	if err := format.Node(&declBuf, fset, declarations); err != nil {
   578  		return nil, nil, err
   579  	}
   580  	if err := format.Node(&replaceBuf, fset, extractedFunCall); err != nil {
   581  		return nil, nil, err
   582  	}
   583  	if ifReturn != nil {
   584  		if err := format.Node(&ifBuf, fset, ifReturn); err != nil {
   585  			return nil, nil, err
   586  		}
   587  	}
   588  	if err := format.Node(&newFuncBuf, fset, newFunc); err != nil {
   589  		return nil, nil, err
   590  	}
   591  	// Find all the comments within the range and print them to be put somewhere.
   592  	// TODO(suzmue): print these in the extracted function at the correct place.
   593  	for _, cg := range file.Comments {
   594  		if cg.Pos().IsValid() && cg.Pos() < end && cg.Pos() >= start {
   595  			for _, c := range cg.List {
   596  				fmt.Fprintln(&commentBuf, c.Text)
   597  			}
   598  		}
   599  	}
   600  
   601  	// We're going to replace the whole enclosing function,
   602  	// so preserve the text before and after the selected block.
   603  	outerStart, outerEnd, err := safetoken.Offsets(tok, outer.Pos(), outer.End())
   604  	if err != nil {
   605  		return nil, nil, err
   606  	}
   607  	before := src[outerStart:startOffset]
   608  	after := src[endOffset:outerEnd]
   609  	indent, err := calculateIndentation(src, tok, node)
   610  	if err != nil {
   611  		return nil, nil, err
   612  	}
   613  	newLineIndent := "\n" + indent
   614  
   615  	var fullReplacement strings.Builder
   616  	fullReplacement.Write(before)
   617  	if commentBuf.Len() > 0 {
   618  		comments := strings.ReplaceAll(commentBuf.String(), "\n", newLineIndent)
   619  		fullReplacement.WriteString(comments)
   620  	}
   621  	if declBuf.Len() > 0 { // add any initializations, if needed
   622  		initializations := strings.ReplaceAll(declBuf.String(), "\n", newLineIndent) +
   623  			newLineIndent
   624  		fullReplacement.WriteString(initializations)
   625  	}
   626  	fullReplacement.Write(replaceBuf.Bytes()) // call the extracted function
   627  	if ifBuf.Len() > 0 {                      // add the if statement below the function call, if needed
   628  		ifstatement := newLineIndent +
   629  			strings.ReplaceAll(ifBuf.String(), "\n", newLineIndent)
   630  		fullReplacement.WriteString(ifstatement)
   631  	}
   632  	fullReplacement.Write(after)
   633  	fullReplacement.WriteString("\n\n")       // add newlines after the enclosing function
   634  	fullReplacement.Write(newFuncBuf.Bytes()) // insert the extracted function
   635  
   636  	return fset, &analysis.SuggestedFix{
   637  		TextEdits: []analysis.TextEdit{{
   638  			Pos:     outer.Pos(),
   639  			End:     outer.End(),
   640  			NewText: []byte(fullReplacement.String()),
   641  		}},
   642  	}, nil
   643  }
   644  
   645  // isSelector reports if e is the selector expr <x>, <sel>.
   646  func isSelector(e ast.Expr, x, sel string) bool {
   647  	selectorExpr, ok := e.(*ast.SelectorExpr)
   648  	if !ok {
   649  		return false
   650  	}
   651  	ident, ok := selectorExpr.X.(*ast.Ident)
   652  	if !ok {
   653  		return false
   654  	}
   655  	return ident.Name == x && selectorExpr.Sel.Name == sel
   656  }
   657  
   658  // reorderParams reorders the given parameters in-place to follow common Go conventions.
   659  func reorderParams(params []ast.Expr, paramTypes []*ast.Field) {
   660  	// Move Context parameter (if any) to front.
   661  	for i, t := range paramTypes {
   662  		if isSelector(t.Type, "context", "Context") {
   663  			p, t := params[i], paramTypes[i]
   664  			copy(params[1:], params[:i])
   665  			copy(paramTypes[1:], paramTypes[:i])
   666  			params[0], paramTypes[0] = p, t
   667  			break
   668  		}
   669  	}
   670  }
   671  
   672  // adjustRangeForCommentsAndWhiteSpace adjusts the given range to exclude unnecessary leading or
   673  // trailing whitespace characters from selection as well as leading or trailing comments.
   674  // In the following example, each line of the if statement is indented once. There are also two
   675  // extra spaces after the sclosing bracket before the line break and a comment.
   676  //
   677  // \tif (true) {
   678  // \t    _ = 1
   679  // \t} // hello \n
   680  //
   681  // By default, a valid range begins at 'if' and ends at the first whitespace character
   682  // after the '}'. But, users are likely to highlight full lines rather than adjusting
   683  // their cursors for whitespace. To support this use case, we must manually adjust the
   684  // ranges to match the correct AST node. In this particular example, we would adjust
   685  // rng.Start forward to the start of 'if' and rng.End backward to after '}'.
   686  func adjustRangeForCommentsAndWhiteSpace(tok *token.File, start, end token.Pos, content []byte, file *ast.File) (token.Pos, token.Pos, error) {
   687  	// Adjust the end of the range to after leading whitespace and comments.
   688  	prevStart := token.NoPos
   689  	startComment := sort.Search(len(file.Comments), func(i int) bool {
   690  		// Find the index for the first comment that ends after range start.
   691  		return file.Comments[i].End() > start
   692  	})
   693  	for prevStart != start {
   694  		prevStart = start
   695  		// If start is within a comment, move start to the end
   696  		// of the comment group.
   697  		if startComment < len(file.Comments) && file.Comments[startComment].Pos() <= start && start < file.Comments[startComment].End() {
   698  			start = file.Comments[startComment].End()
   699  			startComment++
   700  		}
   701  		// Move forwards to find a non-whitespace character.
   702  		offset, err := safetoken.Offset(tok, start)
   703  		if err != nil {
   704  			return 0, 0, err
   705  		}
   706  		for offset < len(content) && isGoWhiteSpace(content[offset]) {
   707  			offset++
   708  		}
   709  		start = tok.Pos(offset)
   710  	}
   711  
   712  	// Adjust the end of the range to before trailing whitespace and comments.
   713  	prevEnd := token.NoPos
   714  	endComment := sort.Search(len(file.Comments), func(i int) bool {
   715  		// Find the index for the first comment that ends after the range end.
   716  		return file.Comments[i].End() >= end
   717  	})
   718  	// Search will return n if not found, so we need to adjust if there are no
   719  	// comments that would match.
   720  	if endComment == len(file.Comments) {
   721  		endComment = -1
   722  	}
   723  	for prevEnd != end {
   724  		prevEnd = end
   725  		// If end is within a comment, move end to the start
   726  		// of the comment group.
   727  		if endComment >= 0 && file.Comments[endComment].Pos() < end && end <= file.Comments[endComment].End() {
   728  			end = file.Comments[endComment].Pos()
   729  			endComment--
   730  		}
   731  		// Move backwards to find a non-whitespace character.
   732  		offset, err := safetoken.Offset(tok, end)
   733  		if err != nil {
   734  			return 0, 0, err
   735  		}
   736  		for offset > 0 && isGoWhiteSpace(content[offset-1]) {
   737  			offset--
   738  		}
   739  		end = tok.Pos(offset)
   740  	}
   741  
   742  	return start, end, nil
   743  }
   744  
   745  // isGoWhiteSpace returns true if b is a considered white space in
   746  // Go as defined by scanner.GoWhitespace.
   747  func isGoWhiteSpace(b byte) bool {
   748  	return uint64(scanner.GoWhitespace)&(1<<uint(b)) != 0
   749  }
   750  
   751  // findParent finds the parent AST node of the given target node, if the target is a
   752  // descendant of the starting node.
   753  func findParent(start ast.Node, target ast.Node) ast.Node {
   754  	var parent ast.Node
   755  	analysisinternal.WalkASTWithParent(start, func(n, p ast.Node) bool {
   756  		if n == target {
   757  			parent = p
   758  			return false
   759  		}
   760  		return true
   761  	})
   762  	return parent
   763  }
   764  
   765  // variable describes the status of a variable within a selection.
   766  type variable struct {
   767  	obj types.Object
   768  
   769  	// free reports whether the variable is a free variable, meaning it should
   770  	// be a parameter to the extracted function.
   771  	free bool
   772  
   773  	// assigned reports whether the variable is assigned to in the selection.
   774  	assigned bool
   775  
   776  	// defined reports whether the variable is defined in the selection.
   777  	defined bool
   778  }
   779  
   780  // collectFreeVars maps each identifier in the given range to whether it is "free."
   781  // Given a range, a variable in that range is defined as "free" if it is declared
   782  // outside of the range and neither at the file scope nor package scope. These free
   783  // variables will be used as arguments in the extracted function. It also returns a
   784  // list of identifiers that may need to be returned by the extracted function.
   785  // Some of the code in this function has been adapted from tools/cmd/guru/freevars.go.
   786  func collectFreeVars(info *types.Info, file *ast.File, fileScope, pkgScope *types.Scope, start, end token.Pos, node ast.Node) ([]*variable, error) {
   787  	// id returns non-nil if n denotes an object that is referenced by the span
   788  	// and defined either within the span or in the lexical environment. The bool
   789  	// return value acts as an indicator for where it was defined.
   790  	id := func(n *ast.Ident) (types.Object, bool) {
   791  		obj := info.Uses[n]
   792  		if obj == nil {
   793  			return info.Defs[n], false
   794  		}
   795  		if obj.Name() == "_" {
   796  			return nil, false // exclude objects denoting '_'
   797  		}
   798  		if _, ok := obj.(*types.PkgName); ok {
   799  			return nil, false // imported package
   800  		}
   801  		if !(file.Pos() <= obj.Pos() && obj.Pos() <= file.End()) {
   802  			return nil, false // not defined in this file
   803  		}
   804  		scope := obj.Parent()
   805  		if scope == nil {
   806  			return nil, false // e.g. interface method, struct field
   807  		}
   808  		if scope == fileScope || scope == pkgScope {
   809  			return nil, false // defined at file or package scope
   810  		}
   811  		if start <= obj.Pos() && obj.Pos() <= end {
   812  			return obj, false // defined within selection => not free
   813  		}
   814  		return obj, true
   815  	}
   816  	// sel returns non-nil if n denotes a selection o.x.y that is referenced by the
   817  	// span and defined either within the span or in the lexical environment. The bool
   818  	// return value acts as an indicator for where it was defined.
   819  	var sel func(n *ast.SelectorExpr) (types.Object, bool)
   820  	sel = func(n *ast.SelectorExpr) (types.Object, bool) {
   821  		switch x := astutil.Unparen(n.X).(type) {
   822  		case *ast.SelectorExpr:
   823  			return sel(x)
   824  		case *ast.Ident:
   825  			return id(x)
   826  		}
   827  		return nil, false
   828  	}
   829  	seen := make(map[types.Object]*variable)
   830  	firstUseIn := make(map[types.Object]token.Pos)
   831  	var vars []types.Object
   832  	ast.Inspect(node, func(n ast.Node) bool {
   833  		if n == nil {
   834  			return false
   835  		}
   836  		if start <= n.Pos() && n.End() <= end {
   837  			var obj types.Object
   838  			var isFree, prune bool
   839  			switch n := n.(type) {
   840  			case *ast.Ident:
   841  				obj, isFree = id(n)
   842  			case *ast.SelectorExpr:
   843  				obj, isFree = sel(n)
   844  				prune = true
   845  			}
   846  			if obj != nil {
   847  				seen[obj] = &variable{
   848  					obj:  obj,
   849  					free: isFree,
   850  				}
   851  				vars = append(vars, obj)
   852  				// Find the first time that the object is used in the selection.
   853  				first, ok := firstUseIn[obj]
   854  				if !ok || n.Pos() < first {
   855  					firstUseIn[obj] = n.Pos()
   856  				}
   857  				if prune {
   858  					return false
   859  				}
   860  			}
   861  		}
   862  		return n.Pos() <= end
   863  	})
   864  
   865  	// Find identifiers that are initialized or whose values are altered at some
   866  	// point in the selected block. For example, in a selected block from lines 2-4,
   867  	// variables x, y, and z are included in assigned. However, in a selected block
   868  	// from lines 3-4, only variables y and z are included in assigned.
   869  	//
   870  	// 1: var a int
   871  	// 2: var x int
   872  	// 3: y := 3
   873  	// 4: z := x + a
   874  	//
   875  	ast.Inspect(node, func(n ast.Node) bool {
   876  		if n == nil {
   877  			return false
   878  		}
   879  		if n.Pos() < start || n.End() > end {
   880  			return n.Pos() <= end
   881  		}
   882  		switch n := n.(type) {
   883  		case *ast.AssignStmt:
   884  			for _, assignment := range n.Lhs {
   885  				lhs, ok := assignment.(*ast.Ident)
   886  				if !ok {
   887  					continue
   888  				}
   889  				obj, _ := id(lhs)
   890  				if obj == nil {
   891  					continue
   892  				}
   893  				if _, ok := seen[obj]; !ok {
   894  					continue
   895  				}
   896  				seen[obj].assigned = true
   897  				if n.Tok != token.DEFINE {
   898  					continue
   899  				}
   900  				// Find identifiers that are defined prior to being used
   901  				// elsewhere in the selection.
   902  				// TODO: Include identifiers that are assigned prior to being
   903  				// used elsewhere in the selection. Then, change the assignment
   904  				// to a definition in the extracted function.
   905  				if firstUseIn[obj] != lhs.Pos() {
   906  					continue
   907  				}
   908  				// Ensure that the object is not used in its own re-definition.
   909  				// For example:
   910  				// var f float64
   911  				// f, e := math.Frexp(f)
   912  				for _, expr := range n.Rhs {
   913  					if referencesObj(info, expr, obj) {
   914  						continue
   915  					}
   916  					if _, ok := seen[obj]; !ok {
   917  						continue
   918  					}
   919  					seen[obj].defined = true
   920  					break
   921  				}
   922  			}
   923  			return false
   924  		case *ast.DeclStmt:
   925  			gen, ok := n.Decl.(*ast.GenDecl)
   926  			if !ok {
   927  				return false
   928  			}
   929  			for _, spec := range gen.Specs {
   930  				vSpecs, ok := spec.(*ast.ValueSpec)
   931  				if !ok {
   932  					continue
   933  				}
   934  				for _, vSpec := range vSpecs.Names {
   935  					obj, _ := id(vSpec)
   936  					if obj == nil {
   937  						continue
   938  					}
   939  					if _, ok := seen[obj]; !ok {
   940  						continue
   941  					}
   942  					seen[obj].assigned = true
   943  				}
   944  			}
   945  			return false
   946  		case *ast.IncDecStmt:
   947  			if ident, ok := n.X.(*ast.Ident); !ok {
   948  				return false
   949  			} else if obj, _ := id(ident); obj == nil {
   950  				return false
   951  			} else {
   952  				if _, ok := seen[obj]; !ok {
   953  					return false
   954  				}
   955  				seen[obj].assigned = true
   956  			}
   957  		}
   958  		return true
   959  	})
   960  	var variables []*variable
   961  	for _, obj := range vars {
   962  		v, ok := seen[obj]
   963  		if !ok {
   964  			return nil, fmt.Errorf("no seen types.Object for %v", obj)
   965  		}
   966  		variables = append(variables, v)
   967  	}
   968  	return variables, nil
   969  }
   970  
   971  // referencesObj checks whether the given object appears in the given expression.
   972  func referencesObj(info *types.Info, expr ast.Expr, obj types.Object) bool {
   973  	var hasObj bool
   974  	ast.Inspect(expr, func(n ast.Node) bool {
   975  		if n == nil {
   976  			return false
   977  		}
   978  		ident, ok := n.(*ast.Ident)
   979  		if !ok {
   980  			return true
   981  		}
   982  		objUse := info.Uses[ident]
   983  		if obj == objUse {
   984  			hasObj = true
   985  			return false
   986  		}
   987  		return false
   988  	})
   989  	return hasObj
   990  }
   991  
   992  type fnExtractParams struct {
   993  	tok        *token.File
   994  	start, end token.Pos
   995  	path       []ast.Node
   996  	outer      *ast.FuncDecl
   997  	node       ast.Node
   998  }
   999  
  1000  // CanExtractFunction reports whether the code in the given range can be
  1001  // extracted to a function.
  1002  func CanExtractFunction(tok *token.File, start, end token.Pos, src []byte, file *ast.File) (*fnExtractParams, bool, bool, error) {
  1003  	if start == end {
  1004  		return nil, false, false, fmt.Errorf("start and end are equal")
  1005  	}
  1006  	var err error
  1007  	start, end, err = adjustRangeForCommentsAndWhiteSpace(tok, start, end, src, file)
  1008  	if err != nil {
  1009  		return nil, false, false, err
  1010  	}
  1011  	path, _ := astutil.PathEnclosingInterval(file, start, end)
  1012  	if len(path) == 0 {
  1013  		return nil, false, false, fmt.Errorf("no path enclosing interval")
  1014  	}
  1015  	// Node that encloses the selection must be a statement.
  1016  	// TODO: Support function extraction for an expression.
  1017  	_, ok := path[0].(ast.Stmt)
  1018  	if !ok {
  1019  		return nil, false, false, fmt.Errorf("node is not a statement")
  1020  	}
  1021  
  1022  	// Find the function declaration that encloses the selection.
  1023  	var outer *ast.FuncDecl
  1024  	for _, p := range path {
  1025  		if p, ok := p.(*ast.FuncDecl); ok {
  1026  			outer = p
  1027  			break
  1028  		}
  1029  	}
  1030  	if outer == nil {
  1031  		return nil, false, false, fmt.Errorf("no enclosing function")
  1032  	}
  1033  
  1034  	// Find the nodes at the start and end of the selection.
  1035  	var startNode, endNode ast.Node
  1036  	ast.Inspect(outer, func(n ast.Node) bool {
  1037  		if n == nil {
  1038  			return false
  1039  		}
  1040  		// Do not override 'start' with a node that begins at the same location
  1041  		// but is nested further from 'outer'.
  1042  		if startNode == nil && n.Pos() == start && n.End() <= end {
  1043  			startNode = n
  1044  		}
  1045  		if endNode == nil && n.End() == end && n.Pos() >= start {
  1046  			endNode = n
  1047  		}
  1048  		return n.Pos() <= end
  1049  	})
  1050  	if startNode == nil || endNode == nil {
  1051  		return nil, false, false, fmt.Errorf("range does not map to AST nodes")
  1052  	}
  1053  	// If the region is a blockStmt, use the first and last nodes in the block
  1054  	// statement.
  1055  	// <rng.start>{ ... }<rng.end> => { <rng.start>...<rng.end> }
  1056  	if blockStmt, ok := startNode.(*ast.BlockStmt); ok {
  1057  		if len(blockStmt.List) == 0 {
  1058  			return nil, false, false, fmt.Errorf("range maps to empty block statement")
  1059  		}
  1060  		startNode, endNode = blockStmt.List[0], blockStmt.List[len(blockStmt.List)-1]
  1061  		start, end = startNode.Pos(), endNode.End()
  1062  	}
  1063  	return &fnExtractParams{
  1064  		tok:   tok,
  1065  		start: start,
  1066  		end:   end,
  1067  		path:  path,
  1068  		outer: outer,
  1069  		node:  startNode,
  1070  	}, true, outer.Recv != nil, nil
  1071  }
  1072  
  1073  // objUsed checks if the object is used within the range. It returns the first
  1074  // occurrence of the object in the range, if it exists.
  1075  func objUsed(info *types.Info, start, end token.Pos, obj types.Object) (bool, *ast.Ident) {
  1076  	var firstUse *ast.Ident
  1077  	for id, objUse := range info.Uses {
  1078  		if obj != objUse {
  1079  			continue
  1080  		}
  1081  		if id.Pos() < start || id.End() > end {
  1082  			continue
  1083  		}
  1084  		if firstUse == nil || id.Pos() < firstUse.Pos() {
  1085  			firstUse = id
  1086  		}
  1087  	}
  1088  	return firstUse != nil, firstUse
  1089  }
  1090  
  1091  // varOverridden traverses the given AST node until we find the given identifier. Then, we
  1092  // examine the occurrence of the given identifier and check for (1) whether the identifier
  1093  // is being redefined. If the identifier is free, we also check for (2) whether the identifier
  1094  // is being reassigned. We will not include an identifier in the return statement of the
  1095  // extracted function if it meets one of the above conditions.
  1096  func varOverridden(info *types.Info, firstUse *ast.Ident, obj types.Object, isFree bool, node ast.Node) bool {
  1097  	var isOverriden bool
  1098  	ast.Inspect(node, func(n ast.Node) bool {
  1099  		if n == nil {
  1100  			return false
  1101  		}
  1102  		assignment, ok := n.(*ast.AssignStmt)
  1103  		if !ok {
  1104  			return true
  1105  		}
  1106  		// A free variable is initialized prior to the selection. We can always reassign
  1107  		// this variable after the selection because it has already been defined.
  1108  		// Conversely, a non-free variable is initialized within the selection. Thus, we
  1109  		// cannot reassign this variable after the selection unless it is initialized and
  1110  		// returned by the extracted function.
  1111  		if !isFree && assignment.Tok == token.ASSIGN {
  1112  			return false
  1113  		}
  1114  		for _, assigned := range assignment.Lhs {
  1115  			ident, ok := assigned.(*ast.Ident)
  1116  			// Check if we found the first use of the identifier.
  1117  			if !ok || ident != firstUse {
  1118  				continue
  1119  			}
  1120  			objUse := info.Uses[ident]
  1121  			if objUse == nil || objUse != obj {
  1122  				continue
  1123  			}
  1124  			// Ensure that the object is not used in its own definition.
  1125  			// For example:
  1126  			// var f float64
  1127  			// f, e := math.Frexp(f)
  1128  			for _, expr := range assignment.Rhs {
  1129  				if referencesObj(info, expr, obj) {
  1130  					return false
  1131  				}
  1132  			}
  1133  			isOverriden = true
  1134  			return false
  1135  		}
  1136  		return false
  1137  	})
  1138  	return isOverriden
  1139  }
  1140  
  1141  // parseBlockStmt generates an AST file from the given text. We then return the portion of the
  1142  // file that represents the text.
  1143  func parseBlockStmt(fset *token.FileSet, src []byte) (*ast.BlockStmt, error) {
  1144  	text := "package main\nfunc _() { " + string(src) + " }"
  1145  	extract, err := parser.ParseFile(fset, "", text, 0)
  1146  	if err != nil {
  1147  		return nil, err
  1148  	}
  1149  	if len(extract.Decls) == 0 {
  1150  		return nil, fmt.Errorf("parsed file does not contain any declarations")
  1151  	}
  1152  	decl, ok := extract.Decls[0].(*ast.FuncDecl)
  1153  	if !ok {
  1154  		return nil, fmt.Errorf("parsed file does not contain expected function declaration")
  1155  	}
  1156  	if decl.Body == nil {
  1157  		return nil, fmt.Errorf("extracted function has no body")
  1158  	}
  1159  	return decl.Body, nil
  1160  }
  1161  
  1162  // generateReturnInfo generates the information we need to adjust the return statements and
  1163  // signature of the extracted function. We prepare names, signatures, and "zero values" that
  1164  // represent the new variables. We also use this information to construct the if statement that
  1165  // is inserted below the call to the extracted function.
  1166  func generateReturnInfo(enclosing *ast.FuncType, pkg *types.Package, path []ast.Node, file *ast.File, info *types.Info, pos token.Pos, hasNonNestedReturns bool) ([]*returnVariable, *ast.IfStmt, error) {
  1167  	var retVars []*returnVariable
  1168  	var cond *ast.Ident
  1169  	if !hasNonNestedReturns {
  1170  		// Generate information for the added bool value.
  1171  		name, _ := generateAvailableIdentifier(pos, path, pkg, info, "shouldReturn", 0)
  1172  		cond = &ast.Ident{Name: name}
  1173  		retVars = append(retVars, &returnVariable{
  1174  			name:    cond,
  1175  			decl:    &ast.Field{Type: ast.NewIdent("bool")},
  1176  			zeroVal: ast.NewIdent("false"),
  1177  		})
  1178  	}
  1179  	// Generate information for the values in the return signature of the enclosing function.
  1180  	if enclosing.Results != nil {
  1181  		idx := 0
  1182  		for _, field := range enclosing.Results.List {
  1183  			typ := info.TypeOf(field.Type)
  1184  			if typ == nil {
  1185  				return nil, nil, fmt.Errorf(
  1186  					"failed type conversion, AST expression: %T", field.Type)
  1187  			}
  1188  			expr := analysisinternal.TypeExpr(file, pkg, typ)
  1189  			if expr == nil {
  1190  				return nil, nil, fmt.Errorf("nil AST expression")
  1191  			}
  1192  			var name string
  1193  			name, idx = generateAvailableIdentifier(pos, path, pkg, info, "returnValue", idx)
  1194  			retVars = append(retVars, &returnVariable{
  1195  				name:    ast.NewIdent(name),
  1196  				decl:    &ast.Field{Type: expr},
  1197  				zeroVal: analysisinternal.ZeroValue(file, pkg, typ),
  1198  			})
  1199  		}
  1200  	}
  1201  	var ifReturn *ast.IfStmt
  1202  	if !hasNonNestedReturns {
  1203  		// Create the return statement for the enclosing function. We must exclude the variable
  1204  		// for the condition of the if statement (cond) from the return statement.
  1205  		ifReturn = &ast.IfStmt{
  1206  			Cond: cond,
  1207  			Body: &ast.BlockStmt{
  1208  				List: []ast.Stmt{&ast.ReturnStmt{Results: getNames(retVars)[1:]}},
  1209  			},
  1210  		}
  1211  	}
  1212  	return retVars, ifReturn, nil
  1213  }
  1214  
  1215  // adjustReturnStatements adds "zero values" of the given types to each return statement
  1216  // in the given AST node.
  1217  func adjustReturnStatements(returnTypes []*ast.Field, seenVars map[types.Object]ast.Expr, file *ast.File, pkg *types.Package, extractedBlock *ast.BlockStmt) error {
  1218  	var zeroVals []ast.Expr
  1219  	// Create "zero values" for each type.
  1220  	for _, returnType := range returnTypes {
  1221  		var val ast.Expr
  1222  		for obj, typ := range seenVars {
  1223  			if typ != returnType.Type {
  1224  				continue
  1225  			}
  1226  			val = analysisinternal.ZeroValue(file, pkg, obj.Type())
  1227  			break
  1228  		}
  1229  		if val == nil {
  1230  			return fmt.Errorf(
  1231  				"could not find matching AST expression for %T", returnType.Type)
  1232  		}
  1233  		zeroVals = append(zeroVals, val)
  1234  	}
  1235  	// Add "zero values" to each return statement.
  1236  	// The bool reports whether the enclosing function should return after calling the
  1237  	// extracted function. We set the bool to 'true' because, if these return statements
  1238  	// execute, the extracted function terminates early, and the enclosing function must
  1239  	// return as well.
  1240  	zeroVals = append(zeroVals, ast.NewIdent("true"))
  1241  	ast.Inspect(extractedBlock, func(n ast.Node) bool {
  1242  		if n == nil {
  1243  			return false
  1244  		}
  1245  		if n, ok := n.(*ast.ReturnStmt); ok {
  1246  			n.Results = append(zeroVals, n.Results...)
  1247  			return false
  1248  		}
  1249  		return true
  1250  	})
  1251  	return nil
  1252  }
  1253  
  1254  // generateFuncCall constructs a call expression for the extracted function, described by the
  1255  // given parameters and return variables.
  1256  func generateFuncCall(hasNonNestedReturn, hasReturnVals bool, params, returns []ast.Expr, name string, token token.Token, selector string) ast.Node {
  1257  	var replace ast.Node
  1258  	callExpr := &ast.CallExpr{
  1259  		Fun:  ast.NewIdent(name),
  1260  		Args: params,
  1261  	}
  1262  	if selector != "" {
  1263  		callExpr = &ast.CallExpr{
  1264  			Fun: &ast.SelectorExpr{
  1265  				X:   ast.NewIdent(selector),
  1266  				Sel: ast.NewIdent(name),
  1267  			},
  1268  			Args: params,
  1269  		}
  1270  	}
  1271  	if hasReturnVals {
  1272  		if hasNonNestedReturn {
  1273  			// Create a return statement that returns the result of the function call.
  1274  			replace = &ast.ReturnStmt{
  1275  				Return:  0,
  1276  				Results: []ast.Expr{callExpr},
  1277  			}
  1278  		} else {
  1279  			// Assign the result of the function call.
  1280  			replace = &ast.AssignStmt{
  1281  				Lhs: returns,
  1282  				Tok: token,
  1283  				Rhs: []ast.Expr{callExpr},
  1284  			}
  1285  		}
  1286  	} else {
  1287  		replace = callExpr
  1288  	}
  1289  	return replace
  1290  }
  1291  
  1292  // initializeVars creates variable declarations, if needed.
  1293  // Our preference is to replace the selected block with an "x, y, z := fn()" style
  1294  // assignment statement. We can use this style when all of the variables in the
  1295  // extracted function's return statement are either not defined prior to the extracted block
  1296  // or can be safely redefined. However, for example, if z is already defined
  1297  // in a different scope, we replace the selected block with:
  1298  //
  1299  // var x int
  1300  // var y string
  1301  // x, y, z = fn()
  1302  func initializeVars(uninitialized []types.Object, retVars []*returnVariable, seenUninitialized map[types.Object]struct{}, seenVars map[types.Object]ast.Expr) []ast.Stmt {
  1303  	var declarations []ast.Stmt
  1304  	for _, obj := range uninitialized {
  1305  		if _, ok := seenUninitialized[obj]; ok {
  1306  			continue
  1307  		}
  1308  		seenUninitialized[obj] = struct{}{}
  1309  		valSpec := &ast.ValueSpec{
  1310  			Names: []*ast.Ident{ast.NewIdent(obj.Name())},
  1311  			Type:  seenVars[obj],
  1312  		}
  1313  		genDecl := &ast.GenDecl{
  1314  			Tok:   token.VAR,
  1315  			Specs: []ast.Spec{valSpec},
  1316  		}
  1317  		declarations = append(declarations, &ast.DeclStmt{Decl: genDecl})
  1318  	}
  1319  	// Each variable added from a return statement in the selection
  1320  	// must be initialized.
  1321  	for i, retVar := range retVars {
  1322  		n := retVar.name.(*ast.Ident)
  1323  		valSpec := &ast.ValueSpec{
  1324  			Names: []*ast.Ident{n},
  1325  			Type:  retVars[i].decl.Type,
  1326  		}
  1327  		genDecl := &ast.GenDecl{
  1328  			Tok:   token.VAR,
  1329  			Specs: []ast.Spec{valSpec},
  1330  		}
  1331  		declarations = append(declarations, &ast.DeclStmt{Decl: genDecl})
  1332  	}
  1333  	return declarations
  1334  }
  1335  
  1336  // getNames returns the names from the given list of returnVariable.
  1337  func getNames(retVars []*returnVariable) []ast.Expr {
  1338  	var names []ast.Expr
  1339  	for _, retVar := range retVars {
  1340  		names = append(names, retVar.name)
  1341  	}
  1342  	return names
  1343  }
  1344  
  1345  // getZeroVals returns the "zero values" from the given list of returnVariable.
  1346  func getZeroVals(retVars []*returnVariable) []ast.Expr {
  1347  	var zvs []ast.Expr
  1348  	for _, retVar := range retVars {
  1349  		zvs = append(zvs, retVar.zeroVal)
  1350  	}
  1351  	return zvs
  1352  }
  1353  
  1354  // getDecls returns the declarations from the given list of returnVariable.
  1355  func getDecls(retVars []*returnVariable) []*ast.Field {
  1356  	var decls []*ast.Field
  1357  	for _, retVar := range retVars {
  1358  		decls = append(decls, retVar.decl)
  1359  	}
  1360  	return decls
  1361  }