1 // Copyright 2024 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 // This file implements go/types-specific scope methods.
6 // These methods do not exist in types2.
7 8 package types
9 10 import "go/token"
11 12 // LookupParent follows the parent chain of scopes starting with s until
13 // it finds a scope where Lookup(name) returns a non-nil object, and then
14 // returns that scope and object. If a valid position pos is provided,
15 // only objects that were declared at or before pos are considered.
16 // If no such scope and object exists, the result is (nil, nil).
17 // The results are guaranteed to be valid only if the type-checked
18 // AST has complete position information.
19 //
20 // Note that obj.Parent() may be different from the returned scope if the
21 // object was inserted into the scope and already had a parent at that
22 // time (see Insert). This can only happen for dot-imported objects
23 // whose parent is the scope of the package that exported them.
24 func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
25 for ; s != nil; s = s.parent {
26 if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || cmpPos(obj.scopePos(), pos) <= 0) {
27 return s, obj
28 }
29 }
30 return nil, nil
31 }
32 33 // Pos and End describe the scope's source code extent [pos, end).
34 // The results are guaranteed to be valid only if the type-checked
35 // AST has complete position information. The extent is undefined
36 // for Universe and package scopes.
37 func (s *Scope) Pos() token.Pos { return s.pos }
38 func (s *Scope) End() token.Pos { return s.end }
39 40 // Contains reports whether pos is within the scope's extent.
41 // The result is guaranteed to be valid only if the type-checked
42 // AST has complete position information.
43 func (s *Scope) Contains(pos token.Pos) bool {
44 return cmpPos(s.pos, pos) <= 0 && cmpPos(pos, s.end) < 0
45 }
46 47 // Innermost returns the innermost (child) scope containing
48 // pos. If pos is not within any scope, the result is nil.
49 // The result is also nil for the Universe scope.
50 // The result is guaranteed to be valid only if the type-checked
51 // AST has complete position information.
52 func (s *Scope) Innermost(pos token.Pos) *Scope {
53 // Package scopes do not have extents since they may be
54 // discontiguous, so iterate over the package's files.
55 if s.parent == Universe {
56 for _, s := range s.children {
57 if inner := s.Innermost(pos); inner != nil {
58 return inner
59 }
60 }
61 }
62 63 if s.Contains(pos) {
64 for _, s := range s.children {
65 if s.Contains(pos) {
66 return s.Innermost(pos)
67 }
68 }
69 return s
70 }
71 return nil
72 }
73