...

Source file src/pkg/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/internal/obj"
     9		"cmd/internal/src"
    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		Importdef *Pkg   // where imported definition was found
    30		Linkname  string // link name
    31	
    32		Pkg  *Pkg
    33		Name string // object name
    34	
    35		// saved and restored by dcopy
    36		Def        *Node    // definition: ONAME OTYPE OPACK or OLITERAL
    37		Block      int32    // blocknumber to catch redeclaration
    38		Lastlineno src.XPos // last declaration for diagnostic
    39	
    40		flags   bitset8
    41		Label   *Node // corresponding label (ephemeral)
    42		Origpkg *Pkg  // original package for . import
    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		symAlgGen // algorithm table has been generated
    51		symFunc   // function symbol; uses internal ABI
    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) AlgGen() bool       { return sym.flags&symAlgGen != 0 }
    59	func (sym *Sym) Func() bool         { return sym.flags&symFunc != 0 }
    60	
    61	func (sym *Sym) SetOnExportList(b bool) { sym.flags.set(symOnExportList, b) }
    62	func (sym *Sym) SetUniq(b bool)         { sym.flags.set(symUniq, b) }
    63	func (sym *Sym) SetSiggen(b bool)       { sym.flags.set(symSiggen, b) }
    64	func (sym *Sym) SetAsm(b bool)          { sym.flags.set(symAsm, b) }
    65	func (sym *Sym) SetAlgGen(b bool)       { sym.flags.set(symAlgGen, b) }
    66	func (sym *Sym) SetFunc(b bool)         { sym.flags.set(symFunc, b) }
    67	
    68	func (sym *Sym) IsBlank() bool {
    69		return sym != nil && sym.Name == "_"
    70	}
    71	
    72	func (sym *Sym) LinksymName() string {
    73		if sym.IsBlank() {
    74			return "_"
    75		}
    76		if sym.Linkname != "" {
    77			return sym.Linkname
    78		}
    79		return sym.Pkg.Prefix + "." + sym.Name
    80	}
    81	
    82	func (sym *Sym) Linksym() *obj.LSym {
    83		if sym == nil {
    84			return nil
    85		}
    86		if sym.Func() {
    87			// This is a function symbol. Mark it as "internal ABI".
    88			return Ctxt.LookupABI(sym.LinksymName(), obj.ABIInternal)
    89		}
    90		return Ctxt.Lookup(sym.LinksymName())
    91	}
    92	
    93	// Less reports whether symbol a is ordered before symbol b.
    94	//
    95	// Symbols are ordered exported before non-exported, then by name, and
    96	// finally (for non-exported symbols) by package height and path.
    97	//
    98	// Ordering by package height is necessary to establish a consistent
    99	// ordering for non-exported names with the same spelling but from
   100	// different packages. We don't necessarily know the path for the
   101	// package being compiled, but by definition it will have a height
   102	// greater than any other packages seen within the compilation unit.
   103	// For more background, see issue #24693.
   104	func (a *Sym) Less(b *Sym) bool {
   105		if a == b {
   106			return false
   107		}
   108	
   109		// Exported symbols before non-exported.
   110		ea := IsExported(a.Name)
   111		eb := IsExported(b.Name)
   112		if ea != eb {
   113			return ea
   114		}
   115	
   116		// Order by name and then (for non-exported names) by package
   117		// height and path.
   118		if a.Name != b.Name {
   119			return a.Name < b.Name
   120		}
   121		if !ea {
   122			if a.Pkg.Height != b.Pkg.Height {
   123				return a.Pkg.Height < b.Pkg.Height
   124			}
   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	

View as plain text