scope2.go raw

   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