1
2
3
4
5 package astutil
6
7
8
9 import (
10 "fmt"
11 "go/ast"
12 "go/token"
13 "sort"
14
15 "golang.org/x/tools/internal/typeparams"
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) {
63
64
65
66 var visit func(node ast.Node) bool
67 visit = func(node ast.Node) bool {
68 path = append(path, node)
69
70 nodePos := node.Pos()
71 nodeEnd := node.End()
72
73
74
75
76 if start < nodePos {
77 start = nodePos
78 }
79 if end > nodeEnd {
80 end = nodeEnd
81 }
82
83
84 children := childrenOf(node)
85 l := len(children)
86 for i, child := range children {
87
88 childPos := child.Pos()
89 childEnd := child.End()
90
91
92 augPos := childPos
93 augEnd := childEnd
94 if i > 0 {
95 augPos = children[i-1].End()
96 }
97 if i < l-1 {
98 nextChildPos := children[i+1].Pos()
99
100 if start >= augEnd && end <= nextChildPos {
101 return false
102 }
103 augEnd = nextChildPos
104 }
105
106
107
108
109
110 if augPos <= start && end <= augEnd {
111 _, isToken := child.(tokenNode)
112 return isToken || visit(child)
113 }
114
115
116
117
118 if start < childEnd && end > augEnd {
119 break
120 }
121 }
122
123
124
125
126
127
128
129
130 if start == nodePos && end == nodeEnd {
131 return true
132 }
133
134 return false
135 }
136
137
138 if start > end {
139 start, end = end, start
140 }
141
142 if start < root.End() && end > root.Pos() {
143 if start == end {
144 end = start + 1
145 }
146 exact = visit(root)
147
148
149 for i, l := 0, len(path); i < l/2; i++ {
150 path[i], path[l-1-i] = path[l-1-i], path[i]
151 }
152 } else {
153
154
155
156 path = append(path, root)
157 }
158
159 return
160 }
161
162
163
164
165 type tokenNode struct {
166 pos token.Pos
167 end token.Pos
168 }
169
170 func (n tokenNode) Pos() token.Pos {
171 return n.pos
172 }
173
174 func (n tokenNode) End() token.Pos {
175 return n.end
176 }
177
178 func tok(pos token.Pos, len int) ast.Node {
179 return tokenNode{pos, pos + token.Pos(len)}
180 }
181
182
183
184
185 func childrenOf(n ast.Node) []ast.Node {
186 var children []ast.Node
187
188
189 ast.Inspect(n, func(node ast.Node) bool {
190 if node == n {
191 return true
192 }
193 if node != nil {
194 children = append(children, node)
195 }
196 return false
197 })
198
199
200 switch n := n.(type) {
201 case *ast.ArrayType:
202 children = append(children,
203 tok(n.Lbrack, len("[")),
204 tok(n.Elt.End(), len("]")))
205
206 case *ast.AssignStmt:
207 children = append(children,
208 tok(n.TokPos, len(n.Tok.String())))
209
210 case *ast.BasicLit:
211 children = append(children,
212 tok(n.ValuePos, len(n.Value)))
213
214 case *ast.BinaryExpr:
215 children = append(children, tok(n.OpPos, len(n.Op.String())))
216
217 case *ast.BlockStmt:
218 children = append(children,
219 tok(n.Lbrace, len("{")),
220 tok(n.Rbrace, len("}")))
221
222 case *ast.BranchStmt:
223 children = append(children,
224 tok(n.TokPos, len(n.Tok.String())))
225
226 case *ast.CallExpr:
227 children = append(children,
228 tok(n.Lparen, len("(")),
229 tok(n.Rparen, len(")")))
230 if n.Ellipsis != 0 {
231 children = append(children, tok(n.Ellipsis, len("...")))
232 }
233
234 case *ast.CaseClause:
235 if n.List == nil {
236 children = append(children,
237 tok(n.Case, len("default")))
238 } else {
239 children = append(children,
240 tok(n.Case, len("case")))
241 }
242 children = append(children, tok(n.Colon, len(":")))
243
244 case *ast.ChanType:
245 switch n.Dir {
246 case ast.RECV:
247 children = append(children, tok(n.Begin, len("<-chan")))
248 case ast.SEND:
249 children = append(children, tok(n.Begin, len("chan<-")))
250 case ast.RECV | ast.SEND:
251 children = append(children, tok(n.Begin, len("chan")))
252 }
253
254 case *ast.CommClause:
255 if n.Comm == nil {
256 children = append(children,
257 tok(n.Case, len("default")))
258 } else {
259 children = append(children,
260 tok(n.Case, len("case")))
261 }
262 children = append(children, tok(n.Colon, len(":")))
263
264 case *ast.Comment:
265
266
267 case *ast.CommentGroup:
268
269
270 case *ast.CompositeLit:
271 children = append(children,
272 tok(n.Lbrace, len("{")),
273 tok(n.Rbrace, len("{")))
274
275 case *ast.DeclStmt:
276
277
278 case *ast.DeferStmt:
279 children = append(children,
280 tok(n.Defer, len("defer")))
281
282 case *ast.Ellipsis:
283 children = append(children,
284 tok(n.Ellipsis, len("...")))
285
286 case *ast.EmptyStmt:
287
288
289 case *ast.ExprStmt:
290
291
292 case *ast.Field:
293
294
295 case *ast.FieldList:
296 children = append(children,
297 tok(n.Opening, len("(")),
298 tok(n.Closing, len(")")))
299
300 case *ast.File:
301
302 children = append(children,
303 tok(n.Package, len("package")))
304
305 case *ast.ForStmt:
306 children = append(children,
307 tok(n.For, len("for")))
308
309 case *ast.FuncDecl:
310
311
312
313
314
315
316
317
318
319 children = nil
320 children = append(children, tok(n.Type.Func, len("func")))
321 if n.Recv != nil {
322 children = append(children, n.Recv)
323 }
324 children = append(children, n.Name)
325 if tparams := typeparams.ForFuncType(n.Type); tparams != nil {
326 children = append(children, tparams)
327 }
328 if n.Type.Params != nil {
329 children = append(children, n.Type.Params)
330 }
331 if n.Type.Results != nil {
332 children = append(children, n.Type.Results)
333 }
334 if n.Body != nil {
335 children = append(children, n.Body)
336 }
337
338 case *ast.FuncLit:
339
340
341 case *ast.FuncType:
342 if n.Func != 0 {
343 children = append(children,
344 tok(n.Func, len("func")))
345 }
346
347 case *ast.GenDecl:
348 children = append(children,
349 tok(n.TokPos, len(n.Tok.String())))
350 if n.Lparen != 0 {
351 children = append(children,
352 tok(n.Lparen, len("(")),
353 tok(n.Rparen, len(")")))
354 }
355
356 case *ast.GoStmt:
357 children = append(children,
358 tok(n.Go, len("go")))
359
360 case *ast.Ident:
361 children = append(children,
362 tok(n.NamePos, len(n.Name)))
363
364 case *ast.IfStmt:
365 children = append(children,
366 tok(n.If, len("if")))
367
368 case *ast.ImportSpec:
369
370
371 case *ast.IncDecStmt:
372 children = append(children,
373 tok(n.TokPos, len(n.Tok.String())))
374
375 case *ast.IndexExpr:
376 children = append(children,
377 tok(n.Lbrack, len("[")),
378 tok(n.Rbrack, len("]")))
379
380 case *typeparams.IndexListExpr:
381 children = append(children,
382 tok(n.Lbrack, len("[")),
383 tok(n.Rbrack, len("]")))
384
385 case *ast.InterfaceType:
386 children = append(children,
387 tok(n.Interface, len("interface")))
388
389 case *ast.KeyValueExpr:
390 children = append(children,
391 tok(n.Colon, len(":")))
392
393 case *ast.LabeledStmt:
394 children = append(children,
395 tok(n.Colon, len(":")))
396
397 case *ast.MapType:
398 children = append(children,
399 tok(n.Map, len("map")))
400
401 case *ast.ParenExpr:
402 children = append(children,
403 tok(n.Lparen, len("(")),
404 tok(n.Rparen, len(")")))
405
406 case *ast.RangeStmt:
407 children = append(children,
408 tok(n.For, len("for")),
409 tok(n.TokPos, len(n.Tok.String())))
410
411 case *ast.ReturnStmt:
412 children = append(children,
413 tok(n.Return, len("return")))
414
415 case *ast.SelectStmt:
416 children = append(children,
417 tok(n.Select, len("select")))
418
419 case *ast.SelectorExpr:
420
421
422 case *ast.SendStmt:
423 children = append(children,
424 tok(n.Arrow, len("<-")))
425
426 case *ast.SliceExpr:
427 children = append(children,
428 tok(n.Lbrack, len("[")),
429 tok(n.Rbrack, len("]")))
430
431 case *ast.StarExpr:
432 children = append(children, tok(n.Star, len("*")))
433
434 case *ast.StructType:
435 children = append(children, tok(n.Struct, len("struct")))
436
437 case *ast.SwitchStmt:
438 children = append(children, tok(n.Switch, len("switch")))
439
440 case *ast.TypeAssertExpr:
441 children = append(children,
442 tok(n.Lparen-1, len(".")),
443 tok(n.Lparen, len("(")),
444 tok(n.Rparen, len(")")))
445
446 case *ast.TypeSpec:
447
448
449 case *ast.TypeSwitchStmt:
450 children = append(children, tok(n.Switch, len("switch")))
451
452 case *ast.UnaryExpr:
453 children = append(children, tok(n.OpPos, len(n.Op.String())))
454
455 case *ast.ValueSpec:
456
457
458 case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt:
459
460 }
461
462
463
464
465
466 sort.Sort(byPos(children))
467
468 return children
469 }
470
471 type byPos []ast.Node
472
473 func (sl byPos) Len() int {
474 return len(sl)
475 }
476 func (sl byPos) Less(i, j int) bool {
477 return sl[i].Pos() < sl[j].Pos()
478 }
479 func (sl byPos) Swap(i, j int) {
480 sl[i], sl[j] = sl[j], sl[i]
481 }
482
483
484
485
486
487
488
489 func NodeDescription(n ast.Node) string {
490 switch n := n.(type) {
491 case *ast.ArrayType:
492 return "array type"
493 case *ast.AssignStmt:
494 return "assignment"
495 case *ast.BadDecl:
496 return "bad declaration"
497 case *ast.BadExpr:
498 return "bad expression"
499 case *ast.BadStmt:
500 return "bad statement"
501 case *ast.BasicLit:
502 return "basic literal"
503 case *ast.BinaryExpr:
504 return fmt.Sprintf("binary %s operation", n.Op)
505 case *ast.BlockStmt:
506 return "block"
507 case *ast.BranchStmt:
508 switch n.Tok {
509 case token.BREAK:
510 return "break statement"
511 case token.CONTINUE:
512 return "continue statement"
513 case token.GOTO:
514 return "goto statement"
515 case token.FALLTHROUGH:
516 return "fall-through statement"
517 }
518 case *ast.CallExpr:
519 if len(n.Args) == 1 && !n.Ellipsis.IsValid() {
520 return "function call (or conversion)"
521 }
522 return "function call"
523 case *ast.CaseClause:
524 return "case clause"
525 case *ast.ChanType:
526 return "channel type"
527 case *ast.CommClause:
528 return "communication clause"
529 case *ast.Comment:
530 return "comment"
531 case *ast.CommentGroup:
532 return "comment group"
533 case *ast.CompositeLit:
534 return "composite literal"
535 case *ast.DeclStmt:
536 return NodeDescription(n.Decl) + " statement"
537 case *ast.DeferStmt:
538 return "defer statement"
539 case *ast.Ellipsis:
540 return "ellipsis"
541 case *ast.EmptyStmt:
542 return "empty statement"
543 case *ast.ExprStmt:
544 return "expression statement"
545 case *ast.Field:
546
547
548
549
550
551
552 return "field/method/parameter"
553 case *ast.FieldList:
554 return "field/method/parameter list"
555 case *ast.File:
556 return "source file"
557 case *ast.ForStmt:
558 return "for loop"
559 case *ast.FuncDecl:
560 return "function declaration"
561 case *ast.FuncLit:
562 return "function literal"
563 case *ast.FuncType:
564 return "function type"
565 case *ast.GenDecl:
566 switch n.Tok {
567 case token.IMPORT:
568 return "import declaration"
569 case token.CONST:
570 return "constant declaration"
571 case token.TYPE:
572 return "type declaration"
573 case token.VAR:
574 return "variable declaration"
575 }
576 case *ast.GoStmt:
577 return "go statement"
578 case *ast.Ident:
579 return "identifier"
580 case *ast.IfStmt:
581 return "if statement"
582 case *ast.ImportSpec:
583 return "import specification"
584 case *ast.IncDecStmt:
585 if n.Tok == token.INC {
586 return "increment statement"
587 }
588 return "decrement statement"
589 case *ast.IndexExpr:
590 return "index expression"
591 case *typeparams.IndexListExpr:
592 return "index list expression"
593 case *ast.InterfaceType:
594 return "interface type"
595 case *ast.KeyValueExpr:
596 return "key/value association"
597 case *ast.LabeledStmt:
598 return "statement label"
599 case *ast.MapType:
600 return "map type"
601 case *ast.Package:
602 return "package"
603 case *ast.ParenExpr:
604 return "parenthesized " + NodeDescription(n.X)
605 case *ast.RangeStmt:
606 return "range loop"
607 case *ast.ReturnStmt:
608 return "return statement"
609 case *ast.SelectStmt:
610 return "select statement"
611 case *ast.SelectorExpr:
612 return "selector"
613 case *ast.SendStmt:
614 return "channel send"
615 case *ast.SliceExpr:
616 return "slice expression"
617 case *ast.StarExpr:
618 return "*-operation"
619 case *ast.StructType:
620 return "struct type"
621 case *ast.SwitchStmt:
622 return "switch statement"
623 case *ast.TypeAssertExpr:
624 return "type assertion"
625 case *ast.TypeSpec:
626 return "type specification"
627 case *ast.TypeSwitchStmt:
628 return "type switch"
629 case *ast.UnaryExpr:
630 return fmt.Sprintf("unary %s operation", n.Op)
631 case *ast.ValueSpec:
632 return "value specification"
633
634 }
635 panic(fmt.Sprintf("unexpected node type: %T", n))
636 }
637
View as plain text