github.com/gmemcc/yaegi@v0.12.1-0.20221128122509-aa99124c5d16/internal/cmd/extract/types/object.go (about) 1 // Copyright 2013 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 "bytes" 9 "fmt" 10 "go/constant" 11 "go/token" 12 ) 13 14 // An Object describes a named language entity such as a package, 15 // constant, type, variable, function (incl. methods), or label. 16 // All objects implement the Object interface. 17 // 18 type Object interface { 19 Parent() *Scope // scope in which this object is declared; nil for methods and struct fields 20 Pos() token.Pos // position of object identifier in declaration 21 Pkg() *Package // package to which this object belongs; nil for labels and objects in the Universe scope 22 Name() string // package local object name 23 Type() Type // object type 24 Exported() bool // reports whether the name starts with a capital letter 25 Id() string // object name if exported, qualified name if not exported (see func Id) 26 27 // String returns a human-readable string of the object. 28 String() string 29 30 // order reflects a package-level object's source order: if object 31 // a is before object b in the source, then a.order() < b.order(). 32 // order returns a value > 0 for package-level objects; it returns 33 // 0 for all other objects (including objects in file scopes). 34 order() uint32 35 36 // color returns the object's color. 37 color() color 38 39 // setOrder sets the order number of the object. It must be > 0. 40 setOrder(uint32) 41 42 // setColor sets the object's color. It must not be white. 43 setColor(color color) 44 45 // setParent sets the parent scope of the object. 46 setParent(*Scope) 47 48 // sameId reports whether obj.Id() and Id(pkg, name) are the same. 49 sameId(pkg *Package, name string) bool 50 51 // scopePos returns the start position of the scope of this Object 52 scopePos() token.Pos 53 54 // setScopePos sets the start position of the scope for this Object. 55 setScopePos(pos token.Pos) 56 } 57 58 // Id returns name if it is exported, otherwise it 59 // returns the name qualified with the package path. 60 func Id(pkg *Package, name string) string { 61 if token.IsExported(name) { 62 return name 63 } 64 // unexported names need the package path for differentiation 65 // (if there's no package, make sure we don't start with '.' 66 // as that may change the order of methods between a setup 67 // inside a package and outside a package - which breaks some 68 // tests) 69 path := "_" 70 // pkg is nil for objects in Universe scope and possibly types 71 // introduced via Eval (see also comment in object.sameId) 72 if pkg != nil && pkg.path != "" { 73 path = pkg.path 74 } 75 return path + "." + name 76 } 77 78 // An object implements the common parts of an Object. 79 type object struct { 80 parent *Scope 81 pos token.Pos 82 pkg *Package 83 name string 84 typ Type 85 order_ uint32 86 color_ color 87 scopePos_ token.Pos 88 } 89 90 // color encodes the color of an object (see Checker.objDecl for details). 91 type color uint32 92 93 // An object may be painted in one of three colors. 94 // Color values other than white or black are considered grey. 95 const ( 96 white color = iota 97 black 98 grey // must be > white and black 99 ) 100 101 func (c color) String() string { 102 switch c { 103 case white: 104 return "white" 105 case black: 106 return "black" 107 default: 108 return "grey" 109 } 110 } 111 112 // colorFor returns the (initial) color for an object depending on 113 // whether its type t is known or not. 114 func colorFor(t Type) color { 115 if t != nil { 116 return black 117 } 118 return white 119 } 120 121 // Parent returns the scope in which the object is declared. 122 // The result is nil for methods and struct fields. 123 func (obj *object) Parent() *Scope { return obj.parent } 124 125 // Pos returns the declaration position of the object's identifier. 126 func (obj *object) Pos() token.Pos { return obj.pos } 127 128 // Pkg returns the package to which the object belongs. 129 // The result is nil for labels and objects in the Universe scope. 130 func (obj *object) Pkg() *Package { return obj.pkg } 131 132 // Name returns the object's (package-local, unqualified) name. 133 func (obj *object) Name() string { return obj.name } 134 135 // Type returns the object's type. 136 func (obj *object) Type() Type { return obj.typ } 137 138 // Exported reports whether the object is exported (starts with a capital letter). 139 // It doesn't take into account whether the object is in a local (function) scope 140 // or not. 141 func (obj *object) Exported() bool { return token.IsExported(obj.name) } 142 143 // Id is a wrapper for Id(obj.Pkg(), obj.Name()). 144 func (obj *object) Id() string { return Id(obj.pkg, obj.name) } 145 146 func (obj *object) String() string { panic("abstract") } 147 func (obj *object) order() uint32 { return obj.order_ } 148 func (obj *object) color() color { return obj.color_ } 149 func (obj *object) scopePos() token.Pos { return obj.scopePos_ } 150 151 func (obj *object) setParent(parent *Scope) { obj.parent = parent } 152 func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order } 153 func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color } 154 func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } 155 156 func (obj *object) sameId(pkg *Package, name string) bool { 157 // spec: 158 // "Two identifiers are different if they are spelled differently, 159 // or if they appear in different packages and are not exported. 160 // Otherwise, they are the same." 161 if name != obj.name { 162 return false 163 } 164 // obj.Name == name 165 if obj.Exported() { 166 return true 167 } 168 // not exported, so packages must be the same (pkg == nil for 169 // fields in Universe scope; this can only happen for types 170 // introduced via Eval) 171 if pkg == nil || obj.pkg == nil { 172 return pkg == obj.pkg 173 } 174 // pkg != nil && obj.pkg != nil 175 return pkg.path == obj.pkg.path 176 } 177 178 // A PkgName represents an imported Go package. 179 // PkgNames don't have a type. 180 type PkgName struct { 181 object 182 imported *Package 183 used bool // set if the package was used 184 } 185 186 // NewPkgName returns a new PkgName object representing an imported package. 187 // The remaining arguments set the attributes found with all Objects. 188 func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName { 189 return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, token.NoPos}, imported, false} 190 } 191 192 // Imported returns the package that was imported. 193 // It is distinct from Pkg(), which is the package containing the import statement. 194 func (obj *PkgName) Imported() *Package { return obj.imported } 195 196 // A Const represents a declared constant. 197 type Const struct { 198 object 199 val constant.Value 200 } 201 202 // NewConst returns a new constant with value val. 203 // The remaining arguments set the attributes found with all Objects. 204 func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const { 205 return &Const{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, val} 206 } 207 208 // Val returns the constant's value. 209 func (obj *Const) Val() constant.Value { return obj.val } 210 211 func (*Const) isDependency() {} // a constant may be a dependency of an initialization expression 212 213 // A TypeName represents a name for a (defined or alias) type. 214 type TypeName struct { 215 object 216 } 217 218 // NewTypeName returns a new type name denoting the given typ. 219 // The remaining arguments set the attributes found with all Objects. 220 // 221 // The typ argument may be a defined (Named) type or an alias type. 222 // It may also be nil such that the returned TypeName can be used as 223 // argument for NewNamed, which will set the TypeName's type as a side- 224 // effect. 225 func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { 226 return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} 227 } 228 229 // IsAlias reports whether obj is an alias name for a type. 230 func (obj *TypeName) IsAlias() bool { 231 switch t := obj.typ.(type) { 232 case nil: 233 return false 234 case *Basic: 235 // unsafe.Pointer is not an alias. 236 if obj.pkg == Unsafe { 237 return false 238 } 239 // Any user-defined type name for a basic type is an alias for a 240 // basic type (because basic types are pre-declared in the Universe 241 // scope, outside any package scope), and so is any type name with 242 // a different name than the name of the basic type it refers to. 243 // Additionally, we need to look for "byte" and "rune" because they 244 // are aliases but have the same names (for better error messages). 245 return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune 246 case *Named: 247 return obj != t.obj 248 default: 249 return true 250 } 251 } 252 253 // A Variable represents a declared variable (including function parameters and results, and struct fields). 254 type Var struct { 255 object 256 embedded bool // if set, the variable is an embedded struct field, and name is the type name 257 isField bool // var is struct field 258 used bool // set if the variable was used 259 } 260 261 // NewVar returns a new variable. 262 // The arguments set the attributes found with all Objects. 263 func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var { 264 return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}} 265 } 266 267 // NewParam returns a new variable representing a function parameter. 268 func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var { 269 return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, used: true} // parameters are always 'used' 270 } 271 272 // NewField returns a new variable representing a struct field. 273 // For embedded fields, the name is the unqualified type name 274 /// under which the field is accessible. 275 func NewField(pos token.Pos, pkg *Package, name string, typ Type, embedded bool) *Var { 276 return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, embedded: embedded, isField: true} 277 } 278 279 // Anonymous reports whether the variable is an embedded field. 280 // Same as Embedded; only present for backward-compatibility. 281 func (obj *Var) Anonymous() bool { return obj.embedded } 282 283 // Embedded reports whether the variable is an embedded field. 284 func (obj *Var) Embedded() bool { return obj.embedded } 285 286 // IsField reports whether the variable is a struct field. 287 func (obj *Var) IsField() bool { return obj.isField } 288 289 func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression 290 291 // A Func represents a declared function, concrete method, or abstract 292 // (interface) method. Its Type() is always a *Signature. 293 // An abstract method may belong to many interfaces due to embedding. 294 type Func struct { 295 object 296 hasPtrRecv bool // only valid for methods that don't have a type yet 297 } 298 299 // NewFunc returns a new function with the given signature, representing 300 // the function's type. 301 func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { 302 // don't store a nil signature 303 var typ Type 304 if sig != nil { 305 typ = sig 306 } 307 return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false} 308 } 309 310 // FullName returns the package- or receiver-type-qualified name of 311 // function or method obj. 312 func (obj *Func) FullName() string { 313 var buf bytes.Buffer 314 writeFuncName(&buf, obj, nil) 315 return buf.String() 316 } 317 318 // Scope returns the scope of the function's body block. 319 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope } 320 321 func (*Func) isDependency() {} // a function may be a dependency of an initialization expression 322 323 // A Label represents a declared label. 324 // Labels don't have a type. 325 type Label struct { 326 object 327 used bool // set if the label was used 328 } 329 330 // NewLabel returns a new label. 331 func NewLabel(pos token.Pos, pkg *Package, name string) *Label { 332 return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid], color_: black}, false} 333 } 334 335 // A Builtin represents a built-in function. 336 // Builtins don't have a valid type. 337 type Builtin struct { 338 object 339 id builtinId 340 } 341 342 func newBuiltin(id builtinId) *Builtin { 343 return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid], color_: black}, id} 344 } 345 346 // Nil represents the predeclared value nil. 347 type Nil struct { 348 object 349 } 350 351 func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { 352 var tname *TypeName 353 typ := obj.Type() 354 355 switch obj := obj.(type) { 356 case *PkgName: 357 fmt.Fprintf(buf, "package %s", obj.Name()) 358 if path := obj.imported.path; path != "" && path != obj.name { 359 fmt.Fprintf(buf, " (%q)", path) 360 } 361 return 362 363 case *Const: 364 buf.WriteString("const") 365 366 case *TypeName: 367 tname = obj 368 buf.WriteString("type") 369 370 case *Var: 371 if obj.isField { 372 buf.WriteString("field") 373 } else { 374 buf.WriteString("var") 375 } 376 377 case *Func: 378 buf.WriteString("func ") 379 writeFuncName(buf, obj, qf) 380 if typ != nil { 381 WriteSignature(buf, typ.(*Signature), qf) 382 } 383 return 384 385 case *Label: 386 buf.WriteString("label") 387 typ = nil 388 389 case *Builtin: 390 buf.WriteString("builtin") 391 typ = nil 392 393 case *Nil: 394 buf.WriteString("nil") 395 return 396 397 default: 398 panic(fmt.Sprintf("writeObject(%T)", obj)) 399 } 400 401 buf.WriteByte(' ') 402 403 // For package-level objects, qualify the name. 404 if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj { 405 writePackage(buf, obj.Pkg(), qf) 406 } 407 buf.WriteString(obj.Name()) 408 409 if typ == nil { 410 return 411 } 412 413 if tname != nil { 414 // We have a type object: Don't print anything more for 415 // basic types since there's no more information (names 416 // are the same; see also comment in TypeName.IsAlias). 417 if _, ok := typ.(*Basic); ok { 418 return 419 } 420 if tname.IsAlias() { 421 buf.WriteString(" =") 422 } else { 423 typ = typ.Underlying() 424 } 425 } 426 427 buf.WriteByte(' ') 428 WriteType(buf, typ, qf) 429 } 430 431 func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) { 432 if pkg == nil { 433 return 434 } 435 var s string 436 if qf != nil { 437 s = qf(pkg) 438 } else { 439 s = pkg.Path() 440 } 441 if s != "" { 442 buf.WriteString(s) 443 buf.WriteByte('.') 444 } 445 } 446 447 // ObjectString returns the string form of obj. 448 // The Qualifier controls the printing of 449 // package-level objects, and may be nil. 450 func ObjectString(obj Object, qf Qualifier) string { 451 var buf bytes.Buffer 452 writeObject(&buf, obj, qf) 453 return buf.String() 454 } 455 456 func (obj *PkgName) String() string { return ObjectString(obj, nil) } 457 func (obj *Const) String() string { return ObjectString(obj, nil) } 458 func (obj *TypeName) String() string { return ObjectString(obj, nil) } 459 func (obj *Var) String() string { return ObjectString(obj, nil) } 460 func (obj *Func) String() string { return ObjectString(obj, nil) } 461 func (obj *Label) String() string { return ObjectString(obj, nil) } 462 func (obj *Builtin) String() string { return ObjectString(obj, nil) } 463 func (obj *Nil) String() string { return ObjectString(obj, nil) } 464 465 func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) { 466 if f.typ != nil { 467 sig := f.typ.(*Signature) 468 if recv := sig.Recv(); recv != nil { 469 buf.WriteByte('(') 470 if _, ok := recv.Type().(*Interface); ok { 471 // gcimporter creates abstract methods of 472 // named interfaces using the interface type 473 // (not the named type) as the receiver. 474 // Don't print it in full. 475 buf.WriteString("interface") 476 } else { 477 WriteType(buf, recv.Type(), qf) 478 } 479 buf.WriteByte(')') 480 buf.WriteByte('.') 481 } else if f.pkg != nil { 482 writePackage(buf, f.pkg, qf) 483 } 484 } 485 buf.WriteString(f.name) 486 }