@@ -225,7 +225,7 @@ func TestCursor_FindNode(t *testing.T) {
225225 inspect := netInspect
226226
227227 // Enumerate all nodes of a particular type,
228- // then check that FindPos can find them,
228+ // then check that FindByPos can find them,
229229 // starting at the root.
230230 //
231231 // (We use BasicLit because they are numerous.)
@@ -263,15 +263,15 @@ func TestCursor_FindNode(t *testing.T) {
263263 }
264264}
265265
266- // TestCursor_FindPos_order ensures that FindPos does not assume files are in Pos order.
267- func TestCursor_FindPos_order (t * testing.T ) {
266+ // TestCursor_FindByPos_order ensures that FindByPos does not assume files are in Pos order.
267+ func TestCursor_FindByPos_order (t * testing.T ) {
268268 // Pick an arbitrary decl.
269269 target := netFiles [7 ].Decls [0 ]
270270
271271 // Find the target decl by its position.
272272 cur , ok := netInspect .Root ().FindByPos (target .Pos (), target .End ())
273273 if ! ok || cur .Node () != target {
274- t .Fatalf ("unshuffled: FindPos (%T) = (%v, %t)" , target , cur , ok )
274+ t .Fatalf ("unshuffled: FindByPos (%T) = (%v, %t)" , target , cur , ok )
275275 }
276276
277277 // Shuffle the files out of Pos order.
@@ -284,7 +284,7 @@ func TestCursor_FindPos_order(t *testing.T) {
284284 inspect := inspector .New (files )
285285 cur , ok = inspect .Root ().FindByPos (target .Pos (), target .End ())
286286 if ! ok || cur .Node () != target {
287- t .Fatalf ("shuffled: FindPos (%T) = (%v, %t)" , target , cur , ok )
287+ t .Fatalf ("shuffled: FindByPos (%T) = (%v, %t)" , target , cur , ok )
288288 }
289289}
290290
@@ -379,6 +379,59 @@ func TestCursor_Edge(t *testing.T) {
379379 }
380380}
381381
382+ // Regression test for mutilple matching nodes in FindByPos (#76872).
383+ func TestCursor_FindByPos_Boundary (t * testing.T ) {
384+ // This test verifies that when a cursor position is on the boundary of two
385+ // adjacent nodes (e.g. "foo|("), FindByPos returns the first node
386+ // encountered in traversal order (which is usually the node "to the left").
387+ //
388+ // Note: The source is intentionally unformatted (no space between ')' and
389+ // '{') to ensure the nodes are strictly adjacent at the boundary.
390+ const src = `package p; func foo(a int){}`
391+ var (
392+ fset = token .NewFileSet ()
393+ f , _ = parser .ParseFile (fset , "p.go" , src , 0 )
394+ tokFile = fset .File (f .FileStart )
395+ inspect = inspector .New ([]* ast.File {f })
396+ )
397+
398+ d := f .Decls [0 ].(* ast.FuncDecl )
399+
400+ format := func (pos token.Pos ) string {
401+ off := tokFile .Offset (pos )
402+ return fmt .Sprintf ("...%s<<>>%s..." , src [off - 1 :off ], src [off :off + 1 ])
403+ }
404+
405+ for _ , test := range []struct {
406+ name string
407+ pos token.Pos
408+ want ast.Node
409+ }{
410+ {
411+ // "foo|(" Ident
412+ pos : d .Type .Params .Opening ,
413+ want : d .Name ,
414+ },
415+ {
416+ // ")|{" FieldList
417+ pos : d .Body .Pos (),
418+ want : d .Type .Params ,
419+ },
420+ } {
421+ cur , ok := inspect .Root ().FindByPos (test .pos , test .pos )
422+ if ! ok {
423+ t .Fatalf ("FindByPos(%d) %s found nothing" , test .pos , format (test .pos ))
424+ }
425+
426+ if cur .Node () != test .want {
427+ t .Errorf ("FindByPos(%d) %s:\n got %T (%v)\n want %T (%v)" ,
428+ test .pos , format (test .pos ),
429+ cur .Node (), cur .Node (),
430+ test .want , test .want )
431+ }
432+ }
433+ }
434+
382435// Regression test for FuncDecl.Type irregularity in FindByPos (#75997).
383436func TestCursor_FindByPos (t * testing.T ) {
384437 // Observe that the range of FuncType has a hole between
@@ -615,12 +668,12 @@ func BenchmarkCursor_FindNode(b *testing.B) {
615668 })
616669
617670 // This method is about 100x (!) faster than Cursor.Preorder.
618- b .Run ("Cursor.FindPos " , func (b * testing.B ) {
671+ b .Run ("Cursor.FindByPos " , func (b * testing.B ) {
619672 needleNode := needle .Node ()
620673 for b .Loop () {
621674 found , ok := root .FindByPos (needleNode .Pos (), needleNode .End ())
622675 if ! ok || found != needle {
623- b .Errorf ("FindPos search failed: got %v, want %v" , found , needle )
676+ b .Errorf ("FindByPos search failed: got %v, want %v" , found , needle )
624677 }
625678 }
626679 })
0 commit comments