enclosing.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. // Copyright 2013 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. package astutil
  5. // This file defines utilities for working with source positions.
  6. import (
  7. "fmt"
  8. "go/ast"
  9. "go/token"
  10. "sort"
  11. )
  12. // PathEnclosingInterval returns the node that encloses the source
  13. // interval [start, end), and all its ancestors up to the AST root.
  14. //
  15. // The definition of "enclosing" used by this function considers
  16. // additional whitespace abutting a node to be enclosed by it.
  17. // In this example:
  18. //
  19. // z := x + y // add them
  20. // <-A->
  21. // <----B----->
  22. //
  23. // the ast.BinaryExpr(+) node is considered to enclose interval B
  24. // even though its [Pos()..End()) is actually only interval A.
  25. // This behaviour makes user interfaces more tolerant of imperfect
  26. // input.
  27. //
  28. // This function treats tokens as nodes, though they are not included
  29. // in the result. e.g. PathEnclosingInterval("+") returns the
  30. // enclosing ast.BinaryExpr("x + y").
  31. //
  32. // If start==end, the 1-char interval following start is used instead.
  33. //
  34. // The 'exact' result is true if the interval contains only path[0]
  35. // and perhaps some adjacent whitespace. It is false if the interval
  36. // overlaps multiple children of path[0], or if it contains only
  37. // interior whitespace of path[0].
  38. // In this example:
  39. //
  40. // z := x + y // add them
  41. // <--C--> <---E-->
  42. // ^
  43. // D
  44. //
  45. // intervals C, D and E are inexact. C is contained by the
  46. // z-assignment statement, because it spans three of its children (:=,
  47. // x, +). So too is the 1-char interval D, because it contains only
  48. // interior whitespace of the assignment. E is considered interior
  49. // whitespace of the BlockStmt containing the assignment.
  50. //
  51. // Precondition: [start, end) both lie within the same file as root.
  52. // TODO(adonovan): return (nil, false) in this case and remove precond.
  53. // Requires FileSet; see loader.tokenFileContainsPos.
  54. //
  55. // Postcondition: path is never nil; it always contains at least 'root'.
  56. //
  57. func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) {
  58. // fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging
  59. // Precondition: node.[Pos..End) and adjoining whitespace contain [start, end).
  60. var visit func(node ast.Node) bool
  61. visit = func(node ast.Node) bool {
  62. path = append(path, node)
  63. nodePos := node.Pos()
  64. nodeEnd := node.End()
  65. // fmt.Printf("visit(%T, %d, %d)\n", node, nodePos, nodeEnd) // debugging
  66. // Intersect [start, end) with interval of node.
  67. if start < nodePos {
  68. start = nodePos
  69. }
  70. if end > nodeEnd {
  71. end = nodeEnd
  72. }
  73. // Find sole child that contains [start, end).
  74. children := childrenOf(node)
  75. l := len(children)
  76. for i, child := range children {
  77. // [childPos, childEnd) is unaugmented interval of child.
  78. childPos := child.Pos()
  79. childEnd := child.End()
  80. // [augPos, augEnd) is whitespace-augmented interval of child.
  81. augPos := childPos
  82. augEnd := childEnd
  83. if i > 0 {
  84. augPos = children[i-1].End() // start of preceding whitespace
  85. }
  86. if i < l-1 {
  87. nextChildPos := children[i+1].Pos()
  88. // Does [start, end) lie between child and next child?
  89. if start >= augEnd && end <= nextChildPos {
  90. return false // inexact match
  91. }
  92. augEnd = nextChildPos // end of following whitespace
  93. }
  94. // fmt.Printf("\tchild %d: [%d..%d)\tcontains interval [%d..%d)?\n",
  95. // i, augPos, augEnd, start, end) // debugging
  96. // Does augmented child strictly contain [start, end)?
  97. if augPos <= start && end <= augEnd {
  98. _, isToken := child.(tokenNode)
  99. return isToken || visit(child)
  100. }
  101. // Does [start, end) overlap multiple children?
  102. // i.e. left-augmented child contains start
  103. // but LR-augmented child does not contain end.
  104. if start < childEnd && end > augEnd {
  105. break
  106. }
  107. }
  108. // No single child contained [start, end),
  109. // so node is the result. Is it exact?
  110. // (It's tempting to put this condition before the
  111. // child loop, but it gives the wrong result in the
  112. // case where a node (e.g. ExprStmt) and its sole
  113. // child have equal intervals.)
  114. if start == nodePos && end == nodeEnd {
  115. return true // exact match
  116. }
  117. return false // inexact: overlaps multiple children
  118. }
  119. if start > end {
  120. start, end = end, start
  121. }
  122. if start < root.End() && end > root.Pos() {
  123. if start == end {
  124. end = start + 1 // empty interval => interval of size 1
  125. }
  126. exact = visit(root)
  127. // Reverse the path:
  128. for i, l := 0, len(path); i < l/2; i++ {
  129. path[i], path[l-1-i] = path[l-1-i], path[i]
  130. }
  131. } else {
  132. // Selection lies within whitespace preceding the
  133. // first (or following the last) declaration in the file.
  134. // The result nonetheless always includes the ast.File.
  135. path = append(path, root)
  136. }
  137. return
  138. }
  139. // tokenNode is a dummy implementation of ast.Node for a single token.
  140. // They are used transiently by PathEnclosingInterval but never escape
  141. // this package.
  142. //
  143. type tokenNode struct {
  144. pos token.Pos
  145. end token.Pos
  146. }
  147. func (n tokenNode) Pos() token.Pos {
  148. return n.pos
  149. }
  150. func (n tokenNode) End() token.Pos {
  151. return n.end
  152. }
  153. func tok(pos token.Pos, len int) ast.Node {
  154. return tokenNode{pos, pos + token.Pos(len)}
  155. }
  156. // childrenOf returns the direct non-nil children of ast.Node n.
  157. // It may include fake ast.Node implementations for bare tokens.
  158. // it is not safe to call (e.g.) ast.Walk on such nodes.
  159. //
  160. func childrenOf(n ast.Node) []ast.Node {
  161. var children []ast.Node
  162. // First add nodes for all true subtrees.
  163. ast.Inspect(n, func(node ast.Node) bool {
  164. if node == n { // push n
  165. return true // recur
  166. }
  167. if node != nil { // push child
  168. children = append(children, node)
  169. }
  170. return false // no recursion
  171. })
  172. // Then add fake Nodes for bare tokens.
  173. switch n := n.(type) {
  174. case *ast.ArrayType:
  175. children = append(children,
  176. tok(n.Lbrack, len("[")),
  177. tok(n.Elt.End(), len("]")))
  178. case *ast.AssignStmt:
  179. children = append(children,
  180. tok(n.TokPos, len(n.Tok.String())))
  181. case *ast.BasicLit:
  182. children = append(children,
  183. tok(n.ValuePos, len(n.Value)))
  184. case *ast.BinaryExpr:
  185. children = append(children, tok(n.OpPos, len(n.Op.String())))
  186. case *ast.BlockStmt:
  187. children = append(children,
  188. tok(n.Lbrace, len("{")),
  189. tok(n.Rbrace, len("}")))
  190. case *ast.BranchStmt:
  191. children = append(children,
  192. tok(n.TokPos, len(n.Tok.String())))
  193. case *ast.CallExpr:
  194. children = append(children,
  195. tok(n.Lparen, len("(")),
  196. tok(n.Rparen, len(")")))
  197. if n.Ellipsis != 0 {
  198. children = append(children, tok(n.Ellipsis, len("...")))
  199. }
  200. case *ast.CaseClause:
  201. if n.List == nil {
  202. children = append(children,
  203. tok(n.Case, len("default")))
  204. } else {
  205. children = append(children,
  206. tok(n.Case, len("case")))
  207. }
  208. children = append(children, tok(n.Colon, len(":")))
  209. case *ast.ChanType:
  210. switch n.Dir {
  211. case ast.RECV:
  212. children = append(children, tok(n.Begin, len("<-chan")))
  213. case ast.SEND:
  214. children = append(children, tok(n.Begin, len("chan<-")))
  215. case ast.RECV | ast.SEND:
  216. children = append(children, tok(n.Begin, len("chan")))
  217. }
  218. case *ast.CommClause:
  219. if n.Comm == nil {
  220. children = append(children,
  221. tok(n.Case, len("default")))
  222. } else {
  223. children = append(children,
  224. tok(n.Case, len("case")))
  225. }
  226. children = append(children, tok(n.Colon, len(":")))
  227. case *ast.Comment:
  228. // nop
  229. case *ast.CommentGroup:
  230. // nop
  231. case *ast.CompositeLit:
  232. children = append(children,
  233. tok(n.Lbrace, len("{")),
  234. tok(n.Rbrace, len("{")))
  235. case *ast.DeclStmt:
  236. // nop
  237. case *ast.DeferStmt:
  238. children = append(children,
  239. tok(n.Defer, len("defer")))
  240. case *ast.Ellipsis:
  241. children = append(children,
  242. tok(n.Ellipsis, len("...")))
  243. case *ast.EmptyStmt:
  244. // nop
  245. case *ast.ExprStmt:
  246. // nop
  247. case *ast.Field:
  248. // TODO(adonovan): Field.{Doc,Comment,Tag}?
  249. case *ast.FieldList:
  250. children = append(children,
  251. tok(n.Opening, len("(")),
  252. tok(n.Closing, len(")")))
  253. case *ast.File:
  254. // TODO test: Doc
  255. children = append(children,
  256. tok(n.Package, len("package")))
  257. case *ast.ForStmt:
  258. children = append(children,
  259. tok(n.For, len("for")))
  260. case *ast.FuncDecl:
  261. // TODO(adonovan): FuncDecl.Comment?
  262. // Uniquely, FuncDecl breaks the invariant that
  263. // preorder traversal yields tokens in lexical order:
  264. // in fact, FuncDecl.Recv precedes FuncDecl.Type.Func.
  265. //
  266. // As a workaround, we inline the case for FuncType
  267. // here and order things correctly.
  268. //
  269. children = nil // discard ast.Walk(FuncDecl) info subtrees
  270. children = append(children, tok(n.Type.Func, len("func")))
  271. if n.Recv != nil {
  272. children = append(children, n.Recv)
  273. }
  274. children = append(children, n.Name)
  275. if n.Type.Params != nil {
  276. children = append(children, n.Type.Params)
  277. }
  278. if n.Type.Results != nil {
  279. children = append(children, n.Type.Results)
  280. }
  281. if n.Body != nil {
  282. children = append(children, n.Body)
  283. }
  284. case *ast.FuncLit:
  285. // nop
  286. case *ast.FuncType:
  287. if n.Func != 0 {
  288. children = append(children,
  289. tok(n.Func, len("func")))
  290. }
  291. case *ast.GenDecl:
  292. children = append(children,
  293. tok(n.TokPos, len(n.Tok.String())))
  294. if n.Lparen != 0 {
  295. children = append(children,
  296. tok(n.Lparen, len("(")),
  297. tok(n.Rparen, len(")")))
  298. }
  299. case *ast.GoStmt:
  300. children = append(children,
  301. tok(n.Go, len("go")))
  302. case *ast.Ident:
  303. children = append(children,
  304. tok(n.NamePos, len(n.Name)))
  305. case *ast.IfStmt:
  306. children = append(children,
  307. tok(n.If, len("if")))
  308. case *ast.ImportSpec:
  309. // TODO(adonovan): ImportSpec.{Doc,EndPos}?
  310. case *ast.IncDecStmt:
  311. children = append(children,
  312. tok(n.TokPos, len(n.Tok.String())))
  313. case *ast.IndexExpr:
  314. children = append(children,
  315. tok(n.Lbrack, len("{")),
  316. tok(n.Rbrack, len("}")))
  317. case *ast.InterfaceType:
  318. children = append(children,
  319. tok(n.Interface, len("interface")))
  320. case *ast.KeyValueExpr:
  321. children = append(children,
  322. tok(n.Colon, len(":")))
  323. case *ast.LabeledStmt:
  324. children = append(children,
  325. tok(n.Colon, len(":")))
  326. case *ast.MapType:
  327. children = append(children,
  328. tok(n.Map, len("map")))
  329. case *ast.ParenExpr:
  330. children = append(children,
  331. tok(n.Lparen, len("(")),
  332. tok(n.Rparen, len(")")))
  333. case *ast.RangeStmt:
  334. children = append(children,
  335. tok(n.For, len("for")),
  336. tok(n.TokPos, len(n.Tok.String())))
  337. case *ast.ReturnStmt:
  338. children = append(children,
  339. tok(n.Return, len("return")))
  340. case *ast.SelectStmt:
  341. children = append(children,
  342. tok(n.Select, len("select")))
  343. case *ast.SelectorExpr:
  344. // nop
  345. case *ast.SendStmt:
  346. children = append(children,
  347. tok(n.Arrow, len("<-")))
  348. case *ast.SliceExpr:
  349. children = append(children,
  350. tok(n.Lbrack, len("[")),
  351. tok(n.Rbrack, len("]")))
  352. case *ast.StarExpr:
  353. children = append(children, tok(n.Star, len("*")))
  354. case *ast.StructType:
  355. children = append(children, tok(n.Struct, len("struct")))
  356. case *ast.SwitchStmt:
  357. children = append(children, tok(n.Switch, len("switch")))
  358. case *ast.TypeAssertExpr:
  359. children = append(children,
  360. tok(n.Lparen-1, len(".")),
  361. tok(n.Lparen, len("(")),
  362. tok(n.Rparen, len(")")))
  363. case *ast.TypeSpec:
  364. // TODO(adonovan): TypeSpec.{Doc,Comment}?
  365. case *ast.TypeSwitchStmt:
  366. children = append(children, tok(n.Switch, len("switch")))
  367. case *ast.UnaryExpr:
  368. children = append(children, tok(n.OpPos, len(n.Op.String())))
  369. case *ast.ValueSpec:
  370. // TODO(adonovan): ValueSpec.{Doc,Comment}?
  371. case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt:
  372. // nop
  373. }
  374. // TODO(adonovan): opt: merge the logic of ast.Inspect() into
  375. // the switch above so we can make interleaved callbacks for
  376. // both Nodes and Tokens in the right order and avoid the need
  377. // to sort.
  378. sort.Sort(byPos(children))
  379. return children
  380. }
  381. type byPos []ast.Node
  382. func (sl byPos) Len() int {
  383. return len(sl)
  384. }
  385. func (sl byPos) Less(i, j int) bool {
  386. return sl[i].Pos() < sl[j].Pos()
  387. }
  388. func (sl byPos) Swap(i, j int) {
  389. sl[i], sl[j] = sl[j], sl[i]
  390. }
  391. // NodeDescription returns a description of the concrete type of n suitable
  392. // for a user interface.
  393. //
  394. // TODO(adonovan): in some cases (e.g. Field, FieldList, Ident,
  395. // StarExpr) we could be much more specific given the path to the AST
  396. // root. Perhaps we should do that.
  397. //
  398. func NodeDescription(n ast.Node) string {
  399. switch n := n.(type) {
  400. case *ast.ArrayType:
  401. return "array type"
  402. case *ast.AssignStmt:
  403. return "assignment"
  404. case *ast.BadDecl:
  405. return "bad declaration"
  406. case *ast.BadExpr:
  407. return "bad expression"
  408. case *ast.BadStmt:
  409. return "bad statement"
  410. case *ast.BasicLit:
  411. return "basic literal"
  412. case *ast.BinaryExpr:
  413. return fmt.Sprintf("binary %s operation", n.Op)
  414. case *ast.BlockStmt:
  415. return "block"
  416. case *ast.BranchStmt:
  417. switch n.Tok {
  418. case token.BREAK:
  419. return "break statement"
  420. case token.CONTINUE:
  421. return "continue statement"
  422. case token.GOTO:
  423. return "goto statement"
  424. case token.FALLTHROUGH:
  425. return "fall-through statement"
  426. }
  427. case *ast.CallExpr:
  428. if len(n.Args) == 1 && !n.Ellipsis.IsValid() {
  429. return "function call (or conversion)"
  430. }
  431. return "function call"
  432. case *ast.CaseClause:
  433. return "case clause"
  434. case *ast.ChanType:
  435. return "channel type"
  436. case *ast.CommClause:
  437. return "communication clause"
  438. case *ast.Comment:
  439. return "comment"
  440. case *ast.CommentGroup:
  441. return "comment group"
  442. case *ast.CompositeLit:
  443. return "composite literal"
  444. case *ast.DeclStmt:
  445. return NodeDescription(n.Decl) + " statement"
  446. case *ast.DeferStmt:
  447. return "defer statement"
  448. case *ast.Ellipsis:
  449. return "ellipsis"
  450. case *ast.EmptyStmt:
  451. return "empty statement"
  452. case *ast.ExprStmt:
  453. return "expression statement"
  454. case *ast.Field:
  455. // Can be any of these:
  456. // struct {x, y int} -- struct field(s)
  457. // struct {T} -- anon struct field
  458. // interface {I} -- interface embedding
  459. // interface {f()} -- interface method
  460. // func (A) func(B) C -- receiver, param(s), result(s)
  461. return "field/method/parameter"
  462. case *ast.FieldList:
  463. return "field/method/parameter list"
  464. case *ast.File:
  465. return "source file"
  466. case *ast.ForStmt:
  467. return "for loop"
  468. case *ast.FuncDecl:
  469. return "function declaration"
  470. case *ast.FuncLit:
  471. return "function literal"
  472. case *ast.FuncType:
  473. return "function type"
  474. case *ast.GenDecl:
  475. switch n.Tok {
  476. case token.IMPORT:
  477. return "import declaration"
  478. case token.CONST:
  479. return "constant declaration"
  480. case token.TYPE:
  481. return "type declaration"
  482. case token.VAR:
  483. return "variable declaration"
  484. }
  485. case *ast.GoStmt:
  486. return "go statement"
  487. case *ast.Ident:
  488. return "identifier"
  489. case *ast.IfStmt:
  490. return "if statement"
  491. case *ast.ImportSpec:
  492. return "import specification"
  493. case *ast.IncDecStmt:
  494. if n.Tok == token.INC {
  495. return "increment statement"
  496. }
  497. return "decrement statement"
  498. case *ast.IndexExpr:
  499. return "index expression"
  500. case *ast.InterfaceType:
  501. return "interface type"
  502. case *ast.KeyValueExpr:
  503. return "key/value association"
  504. case *ast.LabeledStmt:
  505. return "statement label"
  506. case *ast.MapType:
  507. return "map type"
  508. case *ast.Package:
  509. return "package"
  510. case *ast.ParenExpr:
  511. return "parenthesized " + NodeDescription(n.X)
  512. case *ast.RangeStmt:
  513. return "range loop"
  514. case *ast.ReturnStmt:
  515. return "return statement"
  516. case *ast.SelectStmt:
  517. return "select statement"
  518. case *ast.SelectorExpr:
  519. return "selector"
  520. case *ast.SendStmt:
  521. return "channel send"
  522. case *ast.SliceExpr:
  523. return "slice expression"
  524. case *ast.StarExpr:
  525. return "*-operation" // load/store expr or pointer type
  526. case *ast.StructType:
  527. return "struct type"
  528. case *ast.SwitchStmt:
  529. return "switch statement"
  530. case *ast.TypeAssertExpr:
  531. return "type assertion"
  532. case *ast.TypeSpec:
  533. return "type specification"
  534. case *ast.TypeSwitchStmt:
  535. return "type switch"
  536. case *ast.UnaryExpr:
  537. return fmt.Sprintf("unary %s operation", n.Op)
  538. case *ast.ValueSpec:
  539. return "value specification"
  540. }
  541. panic(fmt.Sprintf("unexpected node type: %T", n))
  542. }