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