Source file src/cmd/compile/internal/types/sym.go

     1  // Copyright 2017 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  package types
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/internal/obj"
    10  	"strings"
    11  	"unicode"
    12  	"unicode/utf8"
    13  )
    14  
    15  // Sym represents an object name in a segmented (pkg, name) namespace.
    16  // Most commonly, this is a Go identifier naming an object declared within a package,
    17  // but Syms are also used to name internal synthesized objects.
    18  //
    19  // As an exception, field and method names that are exported use the Sym
    20  // associated with localpkg instead of the package that declared them. This
    21  // allows using Sym pointer equality to test for Go identifier uniqueness when
    22  // handling selector expressions.
    23  //
    24  // Ideally, Sym should be used for representing Go language constructs,
    25  // while cmd/internal/obj.LSym is used for representing emitted artifacts.
    26  //
    27  // NOTE: In practice, things can be messier than the description above
    28  // for various reasons (historical, convenience).
    29  type Sym struct {
    30  	Linkname string // link name
    31  
    32  	Pkg  *Pkg
    33  	Name string // object name
    34  
    35  	// The unique ONAME, OTYPE, OPACK, or OLITERAL node that this symbol is
    36  	// bound to within the current scope. (Most parts of the compiler should
    37  	// prefer passing the Node directly, rather than relying on this field.)
    38  	//
    39  	// Deprecated: New code should avoid depending on Sym.Def. Add
    40  	// mdempsky@ as a reviewer for any CLs involving Sym.Def.
    41  	Def Object
    42  
    43  	flags bitset8
    44  }
    45  
    46  const (
    47  	symOnExportList = 1 << iota // added to exportlist (no need to add again)
    48  	symUniq
    49  	symSiggen // type symbol has been generated
    50  	symAsm    // on asmlist, for writing to -asmhdr
    51  	symFunc   // function symbol
    52  )
    53  
    54  func (sym *Sym) OnExportList() bool { return sym.flags&symOnExportList != 0 }
    55  func (sym *Sym) Uniq() bool         { return sym.flags&symUniq != 0 }
    56  func (sym *Sym) Siggen() bool       { return sym.flags&symSiggen != 0 }
    57  func (sym *Sym) Asm() bool          { return sym.flags&symAsm != 0 }
    58  func (sym *Sym) Func() bool         { return sym.flags&symFunc != 0 }
    59  
    60  func (sym *Sym) SetOnExportList(b bool) { sym.flags.set(symOnExportList, b) }
    61  func (sym *Sym) SetUniq(b bool)         { sym.flags.set(symUniq, b) }
    62  func (sym *Sym) SetSiggen(b bool)       { sym.flags.set(symSiggen, b) }
    63  func (sym *Sym) SetAsm(b bool)          { sym.flags.set(symAsm, b) }
    64  func (sym *Sym) SetFunc(b bool)         { sym.flags.set(symFunc, b) }
    65  
    66  func (sym *Sym) IsBlank() bool {
    67  	return sym != nil && sym.Name == "_"
    68  }
    69  
    70  // Deprecated: This method should not be used directly. Instead, use a
    71  // higher-level abstraction that directly returns the linker symbol
    72  // for a named object. For example, reflectdata.TypeLinksym(t) instead
    73  // of reflectdata.TypeSym(t).Linksym().
    74  func (sym *Sym) Linksym() *obj.LSym {
    75  	abi := obj.ABI0
    76  	if sym.Func() {
    77  		abi = obj.ABIInternal
    78  	}
    79  	return sym.LinksymABI(abi)
    80  }
    81  
    82  // Deprecated: This method should not be used directly. Instead, use a
    83  // higher-level abstraction that directly returns the linker symbol
    84  // for a named object. For example, (*ir.Name).LinksymABI(abi) instead
    85  // of (*ir.Name).Sym().LinksymABI(abi).
    86  func (sym *Sym) LinksymABI(abi obj.ABI) *obj.LSym {
    87  	if sym == nil {
    88  		base.Fatalf("nil symbol")
    89  	}
    90  	if sym.Linkname != "" {
    91  		return base.Linkname(sym.Linkname, abi)
    92  	}
    93  	return base.PkgLinksym(sym.Pkg.Prefix, sym.Name, abi)
    94  }
    95  
    96  // CompareSyms return the ordering of a and b, as for [cmp.Compare].
    97  //
    98  // Symbols are ordered exported before non-exported, then by name, and
    99  // finally (for non-exported symbols) by package path.
   100  func CompareSyms(a, b *Sym) int {
   101  	if a == b {
   102  		return 0
   103  	}
   104  
   105  	// Nil before non-nil.
   106  	if a == nil {
   107  		return -1
   108  	}
   109  	if b == nil {
   110  		return +1
   111  	}
   112  
   113  	// Exported symbols before non-exported.
   114  	ea := IsExported(a.Name)
   115  	eb := IsExported(b.Name)
   116  	if ea != eb {
   117  		if ea {
   118  			return -1
   119  		} else {
   120  			return +1
   121  		}
   122  	}
   123  
   124  	// Order by name and then (for non-exported names) by package
   125  	// height and path.
   126  	if r := strings.Compare(a.Name, b.Name); r != 0 {
   127  		return r
   128  	}
   129  	if !ea {
   130  		return strings.Compare(a.Pkg.Path, b.Pkg.Path)
   131  	}
   132  	return 0
   133  }
   134  
   135  // IsExported reports whether name is an exported Go symbol (that is,
   136  // whether it begins with an upper-case letter).
   137  func IsExported(name string) bool {
   138  	if r := name[0]; r < utf8.RuneSelf {
   139  		return 'A' <= r && r <= 'Z'
   140  	}
   141  	r, _ := utf8.DecodeRuneInString(name)
   142  	return unicode.IsUpper(r)
   143  }
   144  

View as plain text