// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file implements go/types-specific scope methods. // These methods do not exist in types2. package types import "go/token" // LookupParent follows the parent chain of scopes starting with s until // it finds a scope where Lookup(name) returns a non-nil object, and then // returns that scope and object. If a valid position pos is provided, // only objects that were declared at or before pos are considered. // If no such scope and object exists, the result is (nil, nil). // The results are guaranteed to be valid only if the type-checked // AST has complete position information. // // Note that obj.Parent() may be different from the returned scope if the // object was inserted into the scope and already had a parent at that // time (see Insert). This can only happen for dot-imported objects // whose parent is the scope of the package that exported them. func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { for ; s != nil; s = s.parent { if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || cmpPos(obj.scopePos(), pos) <= 0) { return s, obj } } return nil, nil } // Pos and End describe the scope's source code extent [pos, end). // The results are guaranteed to be valid only if the type-checked // AST has complete position information. The extent is undefined // for Universe and package scopes. func (s *Scope) Pos() token.Pos { return s.pos } func (s *Scope) End() token.Pos { return s.end } // Contains reports whether pos is within the scope's extent. // The result is guaranteed to be valid only if the type-checked // AST has complete position information. func (s *Scope) Contains(pos token.Pos) bool { return cmpPos(s.pos, pos) <= 0 && cmpPos(pos, s.end) < 0 } // Innermost returns the innermost (child) scope containing // pos. If pos is not within any scope, the result is nil. // The result is also nil for the Universe scope. // The result is guaranteed to be valid only if the type-checked // AST has complete position information. func (s *Scope) Innermost(pos token.Pos) *Scope { // Package scopes do not have extents since they may be // discontiguous, so iterate over the package's files. if s.parent == Universe { for _, s := range s.children { if inner := s.Innermost(pos); inner != nil { return inner } } } if s.Contains(pos) { for _, s := range s.children { if s.Contains(pos) { return s.Innermost(pos) } } return s } return nil }