| // Copyright 2017 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. |
| |
| package types |
| |
| import ( |
| "cmd/compile/internal/base" |
| "cmd/internal/obj" |
| "unicode" |
| "unicode/utf8" |
| ) |
| |
| // Sym represents an object name in a segmented (pkg, name) namespace. |
| // Most commonly, this is a Go identifier naming an object declared within a package, |
| // but Syms are also used to name internal synthesized objects. |
| // |
| // As an exception, field and method names that are exported use the Sym |
| // associated with localpkg instead of the package that declared them. This |
| // allows using Sym pointer equality to test for Go identifier uniqueness when |
| // handling selector expressions. |
| // |
| // Ideally, Sym should be used for representing Go language constructs, |
| // while cmd/internal/obj.LSym is used for representing emitted artifacts. |
| // |
| // NOTE: In practice, things can be messier than the description above |
| // for various reasons (historical, convenience). |
| type Sym struct { |
| Linkname string // link name |
| |
| Pkg *Pkg |
| Name string // object name |
| |
| // The unique ONAME, OTYPE, OPACK, or OLITERAL node that this symbol is |
| // bound to within the current scope. (Most parts of the compiler should |
| // prefer passing the Node directly, rather than relying on this field.) |
| // |
| // Deprecated: New code should avoid depending on Sym.Def. Add |
| // mdempsky@ as a reviewer for any CLs involving Sym.Def. |
| Def Object |
| |
| flags bitset8 |
| } |
| |
| const ( |
| symOnExportList = 1 << iota // added to exportlist (no need to add again) |
| symUniq |
| symSiggen // type symbol has been generated |
| symAsm // on asmlist, for writing to -asmhdr |
| symFunc // function symbol |
| ) |
| |
| func (sym *Sym) OnExportList() bool { return sym.flags&symOnExportList != 0 } |
| func (sym *Sym) Uniq() bool { return sym.flags&symUniq != 0 } |
| func (sym *Sym) Siggen() bool { return sym.flags&symSiggen != 0 } |
| func (sym *Sym) Asm() bool { return sym.flags&symAsm != 0 } |
| func (sym *Sym) Func() bool { return sym.flags&symFunc != 0 } |
| |
| func (sym *Sym) SetOnExportList(b bool) { sym.flags.set(symOnExportList, b) } |
| func (sym *Sym) SetUniq(b bool) { sym.flags.set(symUniq, b) } |
| func (sym *Sym) SetSiggen(b bool) { sym.flags.set(symSiggen, b) } |
| func (sym *Sym) SetAsm(b bool) { sym.flags.set(symAsm, b) } |
| func (sym *Sym) SetFunc(b bool) { sym.flags.set(symFunc, b) } |
| |
| func (sym *Sym) IsBlank() bool { |
| return sym != nil && sym.Name == "_" |
| } |
| |
| // Deprecated: This method should not be used directly. Instead, use a |
| // higher-level abstraction that directly returns the linker symbol |
| // for a named object. For example, reflectdata.TypeLinksym(t) instead |
| // of reflectdata.TypeSym(t).Linksym(). |
| func (sym *Sym) Linksym() *obj.LSym { |
| abi := obj.ABI0 |
| if sym.Func() { |
| abi = obj.ABIInternal |
| } |
| return sym.LinksymABI(abi) |
| } |
| |
| // Deprecated: This method should not be used directly. Instead, use a |
| // higher-level abstraction that directly returns the linker symbol |
| // for a named object. For example, (*ir.Name).LinksymABI(abi) instead |
| // of (*ir.Name).Sym().LinksymABI(abi). |
| func (sym *Sym) LinksymABI(abi obj.ABI) *obj.LSym { |
| if sym == nil { |
| base.Fatalf("nil symbol") |
| } |
| if sym.Linkname != "" { |
| return base.Linkname(sym.Linkname, abi) |
| } |
| return base.PkgLinksym(sym.Pkg.Prefix, sym.Name, abi) |
| } |
| |
| // Less reports whether symbol a is ordered before symbol b. |
| // |
| // Symbols are ordered exported before non-exported, then by name, and |
| // finally (for non-exported symbols) by package path. |
| func (a *Sym) Less(b *Sym) bool { |
| if a == b { |
| return false |
| } |
| |
| // Nil before non-nil. |
| if a == nil { |
| return true |
| } |
| if b == nil { |
| return false |
| } |
| |
| // Exported symbols before non-exported. |
| ea := IsExported(a.Name) |
| eb := IsExported(b.Name) |
| if ea != eb { |
| return ea |
| } |
| |
| // Order by name and then (for non-exported names) by package |
| // height and path. |
| if a.Name != b.Name { |
| return a.Name < b.Name |
| } |
| if !ea { |
| return a.Pkg.Path < b.Pkg.Path |
| } |
| return false |
| } |
| |
| // IsExported reports whether name is an exported Go symbol (that is, |
| // whether it begins with an upper-case letter). |
| func IsExported(name string) bool { |
| if r := name[0]; r < utf8.RuneSelf { |
| return 'A' <= r && r <= 'Z' |
| } |
| r, _ := utf8.DecodeRuneInString(name) |
| return unicode.IsUpper(r) |
| } |