@@ -22,7 +22,7 @@ import (
22
22
)
23
23
24
24
func extractVariable (fset * token.FileSet , rng span.Range , src []byte , file * ast.File , pkg * types.Package , info * types.Info ) (* analysis.SuggestedFix , error ) {
25
- expr , path , ok , err := canExtractVariable (fset , rng , src , file , pkg , info )
25
+ expr , path , ok , err := canExtractVariable (rng , file )
26
26
if ! ok {
27
27
return nil , fmt .Errorf ("extractVariable: cannot extract %s: %v" , fset .Position (rng .Start ), err )
28
28
}
@@ -78,7 +78,7 @@ func extractVariable(fset *token.FileSet, rng span.Range, src []byte, file *ast.
78
78
79
79
// canExtractVariable reports whether the code in the given range can be
80
80
// extracted to a variable.
81
- 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 ) {
81
+ func canExtractVariable (rng span.Range , file * ast.File ) (ast.Expr , []ast.Node , bool , error ) {
82
82
if rng .Start == rng .End {
83
83
return nil , nil , false , fmt .Errorf ("start and end are equal" )
84
84
}
@@ -156,19 +156,10 @@ type returnVariable struct {
156
156
// of the function and insert this call as well as the extracted function into
157
157
// their proper locations.
158
158
func extractFunction (fset * token.FileSet , rng span.Range , src []byte , file * ast.File , pkg * types.Package , info * types.Info ) (* analysis.SuggestedFix , error ) {
159
- tok := fset .File (file .Pos ())
160
- if tok == nil {
161
- return nil , fmt .Errorf ("extractFunction: no token.File" )
162
- }
163
- rng = adjustRangeForWhitespace (rng , tok , src )
164
- path , _ := astutil .PathEnclosingInterval (file , rng .Start , rng .End )
165
- if len (path ) == 0 {
166
- return nil , fmt .Errorf ("extractFunction: no path enclosing interval" )
167
- }
168
- // Node that encloses the selection must be a statement.
169
- // TODO: Support function extraction for an expression.
170
- if _ , ok := path [0 ].(ast.Stmt ); ! ok {
171
- return nil , fmt .Errorf ("extractFunction: ast.Node is not a statement" )
159
+ tok , path , outer , start , ok , err := canExtractFunction (fset , rng , src , file , info )
160
+ if ! ok {
161
+ return nil , fmt .Errorf ("extractFunction: cannot extract %s: %v" ,
162
+ fset .Position (rng .Start ), err )
172
163
}
173
164
fileScope := info .Scopes [file ]
174
165
if fileScope == nil {
@@ -178,37 +169,6 @@ func extractFunction(fset *token.FileSet, rng span.Range, src []byte, file *ast.
178
169
if pkgScope == nil {
179
170
return nil , fmt .Errorf ("extractFunction: package scope is empty" )
180
171
}
181
- // Find the function declaration that encloses the selection.
182
- var outer * ast.FuncDecl
183
- for _ , p := range path {
184
- if p , ok := p .(* ast.FuncDecl ); ok {
185
- outer = p
186
- break
187
- }
188
- }
189
- if outer == nil {
190
- return nil , fmt .Errorf ("extractFunction: no enclosing function" )
191
- }
192
-
193
- // Find the nodes at the start and end of the selection.
194
- var start , end ast.Node
195
- ast .Inspect (outer , func (n ast.Node ) bool {
196
- if n == nil {
197
- return true
198
- }
199
- // Do not override 'start' with a node that begins at the same location but is
200
- // nested further from 'outer'.
201
- if start == nil && n .Pos () == rng .Start && n .End () <= rng .End {
202
- start = n
203
- }
204
- if end == nil && n .End () == rng .End && n .Pos () >= rng .Start {
205
- end = n
206
- }
207
- return n .Pos () <= rng .End
208
- })
209
- if start == nil || end == nil {
210
- return nil , nil
211
- }
212
172
213
173
// TODO: Support non-nested return statements.
214
174
// A return statement is non-nested if its parent node is equal to the parent node
@@ -237,7 +197,7 @@ func extractFunction(fset *token.FileSet, rng span.Range, src []byte, file *ast.
237
197
return true
238
198
})
239
199
if hasNonNestedReturn {
240
- return nil , fmt .Errorf ("extractFunction: selected bloc kcontains non-nested return" )
200
+ return nil , fmt .Errorf ("extractFunction: selected block contains non-nested return" )
241
201
}
242
202
containsReturnStatement := len (retStmts ) > 0
243
203
@@ -673,25 +633,60 @@ func collectFreeVars(info *types.Info, file *ast.File, fileScope *types.Scope,
673
633
return free , vars , assigned
674
634
}
675
635
676
- // canExtractFunction reports whether the code in the given range can be
677
- // extracted to a function.
678
- // TODO(rstambler): De-duplicate the logic between extractFunction and
679
- // canExtractFunction.
680
- func canExtractFunction (fset * token.FileSet , rng span.Range , src []byte , file * ast.File , pkg * types.Package , info * types.Info ) bool {
636
+ // canExtractFunction reports whether the code in the given range can be extracted to a function.
637
+ func canExtractFunction (fset * token.FileSet , rng span.Range , src []byte , file * ast.File , info * types.Info ) (* token.File , []ast.Node , * ast.FuncDecl , ast.Node , bool , error ) {
681
638
if rng .Start == rng .End {
682
- return false
639
+ return nil , nil , nil , nil , false , fmt . Errorf ( "start and end are equal" )
683
640
}
684
641
tok := fset .File (file .Pos ())
685
642
if tok == nil {
686
- return false
643
+ return nil , nil , nil , nil , false ,
644
+ fmt .Errorf ("no file for pos %v" , fset .Position (file .Pos ()))
687
645
}
688
646
rng = adjustRangeForWhitespace (rng , tok , src )
689
647
path , _ := astutil .PathEnclosingInterval (file , rng .Start , rng .End )
690
648
if len (path ) == 0 {
691
- return false
649
+ return nil , nil , nil , nil , false , fmt . Errorf ( "no path enclosing interval" )
692
650
}
651
+ // Node that encloses the selection must be a statement.
652
+ // TODO: Support function extraction for an expression.
693
653
_ , ok := path [0 ].(ast.Stmt )
694
- return ok
654
+ if ! ok {
655
+ return nil , nil , nil , nil , false , fmt .Errorf ("node is not a statement" )
656
+ }
657
+
658
+ // Find the function declaration that encloses the selection.
659
+ var outer * ast.FuncDecl
660
+ for _ , p := range path {
661
+ if p , ok := p .(* ast.FuncDecl ); ok {
662
+ outer = p
663
+ break
664
+ }
665
+ }
666
+ if outer == nil {
667
+ return nil , nil , nil , nil , false , fmt .Errorf ("no enclosing function" )
668
+ }
669
+
670
+ // Find the nodes at the start and end of the selection.
671
+ var start , end ast.Node
672
+ ast .Inspect (outer , func (n ast.Node ) bool {
673
+ if n == nil {
674
+ return true
675
+ }
676
+ // Do not override 'start' with a node that begins at the same location but is
677
+ // nested further from 'outer'.
678
+ if start == nil && n .Pos () == rng .Start && n .End () <= rng .End {
679
+ start = n
680
+ }
681
+ if end == nil && n .End () == rng .End && n .Pos () >= rng .Start {
682
+ end = n
683
+ }
684
+ return n .Pos () <= rng .End
685
+ })
686
+ if start == nil || end == nil {
687
+ return nil , nil , nil , nil , false , fmt .Errorf ("range does not map to AST nodes" )
688
+ }
689
+ return tok , path , outer , start , true , nil
695
690
}
696
691
697
692
// objUsed checks if the object is used between the given positions.
0 commit comments