gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/golang.org/x/tools/go/gcimporter15/bexport.go (about) 1 // Copyright 2016 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 // Binary package export. 6 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; 7 // see that file for specification of the format. 8 9 package gcimporter 10 11 import ( 12 "bytes" 13 "encoding/binary" 14 "fmt" 15 "go/ast" 16 "go/constant" 17 "go/token" 18 "go/types" 19 "log" 20 "math" 21 "math/big" 22 "sort" 23 "strings" 24 ) 25 26 // If debugFormat is set, each integer and string value is preceded by a marker 27 // and position information in the encoding. This mechanism permits an importer 28 // to recognize immediately when it is out of sync. The importer recognizes this 29 // mode automatically (i.e., it can import export data produced with debugging 30 // support even if debugFormat is not set at the time of import). This mode will 31 // lead to massively larger export data (by a factor of 2 to 3) and should only 32 // be enabled during development and debugging. 33 // 34 // NOTE: This flag is the first flag to enable if importing dies because of 35 // (suspected) format errors, and whenever a change is made to the format. 36 const debugFormat = false // default: false 37 38 // If trace is set, debugging output is printed to std out. 39 const trace = false // default: false 40 41 // Current export format version. Increase with each format change. 42 // 4: type name objects support type aliases, uses aliasTag 43 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) 44 // 2: removed unused bool in ODCL export (compiler only) 45 // 1: header format change (more regular), export package for _ struct fields 46 // 0: Go1.7 encoding 47 const exportVersion = 4 48 49 // trackAllTypes enables cycle tracking for all types, not just named 50 // types. The existing compiler invariants assume that unnamed types 51 // that are not completely set up are not used, or else there are spurious 52 // errors. 53 // If disabled, only named types are tracked, possibly leading to slightly 54 // less efficient encoding in rare cases. It also prevents the export of 55 // some corner-case type declarations (but those are not handled correctly 56 // with with the textual export format either). 57 // TODO(gri) enable and remove once issues caused by it are fixed 58 const trackAllTypes = false 59 60 type exporter struct { 61 fset *token.FileSet 62 out bytes.Buffer 63 64 // object -> index maps, indexed in order of serialization 65 strIndex map[string]int 66 pkgIndex map[*types.Package]int 67 typIndex map[types.Type]int 68 69 // position encoding 70 posInfoFormat bool 71 prevFile string 72 prevLine int 73 74 // debugging support 75 written int // bytes written 76 indent int // for trace 77 } 78 79 // BExportData returns binary export data for pkg. 80 // If no file set is provided, position info will be missing. 81 func BExportData(fset *token.FileSet, pkg *types.Package) []byte { 82 p := exporter{ 83 fset: fset, 84 strIndex: map[string]int{"": 0}, // empty string is mapped to 0 85 pkgIndex: make(map[*types.Package]int), 86 typIndex: make(map[types.Type]int), 87 posInfoFormat: true, // TODO(gri) might become a flag, eventually 88 } 89 90 // write version info 91 // The version string must start with "version %d" where %d is the version 92 // number. Additional debugging information may follow after a blank; that 93 // text is ignored by the importer. 94 p.rawStringln(fmt.Sprintf("version %d", exportVersion)) 95 var debug string 96 if debugFormat { 97 debug = "debug" 98 } 99 p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly 100 p.bool(trackAllTypes) 101 p.bool(p.posInfoFormat) 102 103 // --- generic export data --- 104 105 // populate type map with predeclared "known" types 106 for index, typ := range predeclared { 107 p.typIndex[typ] = index 108 } 109 if len(p.typIndex) != len(predeclared) { 110 log.Fatalf("gcimporter: duplicate entries in type map?") 111 } 112 113 // write package data 114 p.pkg(pkg, true) 115 if trace { 116 p.tracef("\n") 117 } 118 119 // write objects 120 objcount := 0 121 scope := pkg.Scope() 122 for _, name := range scope.Names() { 123 if !ast.IsExported(name) { 124 continue 125 } 126 if trace { 127 p.tracef("\n") 128 } 129 p.obj(scope.Lookup(name)) 130 objcount++ 131 } 132 133 // indicate end of list 134 if trace { 135 p.tracef("\n") 136 } 137 p.tag(endTag) 138 139 // for self-verification only (redundant) 140 p.int(objcount) 141 142 if trace { 143 p.tracef("\n") 144 } 145 146 // --- end of export data --- 147 148 return p.out.Bytes() 149 } 150 151 func (p *exporter) pkg(pkg *types.Package, emptypath bool) { 152 if pkg == nil { 153 log.Fatalf("gcimporter: unexpected nil pkg") 154 } 155 156 // if we saw the package before, write its index (>= 0) 157 if i, ok := p.pkgIndex[pkg]; ok { 158 p.index('P', i) 159 return 160 } 161 162 // otherwise, remember the package, write the package tag (< 0) and package data 163 if trace { 164 p.tracef("P%d = { ", len(p.pkgIndex)) 165 defer p.tracef("} ") 166 } 167 p.pkgIndex[pkg] = len(p.pkgIndex) 168 169 p.tag(packageTag) 170 p.string(pkg.Name()) 171 if emptypath { 172 p.string("") 173 } else { 174 p.string(pkg.Path()) 175 } 176 } 177 178 func (p *exporter) obj(obj types.Object) { 179 switch obj := obj.(type) { 180 case *types.Const: 181 p.tag(constTag) 182 p.pos(obj) 183 p.qualifiedName(obj) 184 p.typ(obj.Type()) 185 p.value(obj.Val()) 186 187 case *types.TypeName: 188 if isAlias(obj) { 189 p.tag(aliasTag) 190 p.pos(obj) 191 p.qualifiedName(obj) 192 } else { 193 p.tag(typeTag) 194 } 195 p.typ(obj.Type()) 196 197 case *types.Var: 198 p.tag(varTag) 199 p.pos(obj) 200 p.qualifiedName(obj) 201 p.typ(obj.Type()) 202 203 case *types.Func: 204 p.tag(funcTag) 205 p.pos(obj) 206 p.qualifiedName(obj) 207 sig := obj.Type().(*types.Signature) 208 p.paramList(sig.Params(), sig.Variadic()) 209 p.paramList(sig.Results(), false) 210 211 default: 212 log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj) 213 } 214 } 215 216 func (p *exporter) pos(obj types.Object) { 217 if !p.posInfoFormat { 218 return 219 } 220 221 file, line := p.fileLine(obj) 222 if file == p.prevFile { 223 // common case: write line delta 224 // delta == 0 means different file or no line change 225 delta := line - p.prevLine 226 p.int(delta) 227 if delta == 0 { 228 p.int(-1) // -1 means no file change 229 } 230 } else { 231 // different file 232 p.int(0) 233 // Encode filename as length of common prefix with previous 234 // filename, followed by (possibly empty) suffix. Filenames 235 // frequently share path prefixes, so this can save a lot 236 // of space and make export data size less dependent on file 237 // path length. The suffix is unlikely to be empty because 238 // file names tend to end in ".go". 239 n := commonPrefixLen(p.prevFile, file) 240 p.int(n) // n >= 0 241 p.string(file[n:]) // write suffix only 242 p.prevFile = file 243 p.int(line) 244 } 245 p.prevLine = line 246 } 247 248 func (p *exporter) fileLine(obj types.Object) (file string, line int) { 249 if p.fset != nil { 250 pos := p.fset.Position(obj.Pos()) 251 file = pos.Filename 252 line = pos.Line 253 } 254 return 255 } 256 257 func commonPrefixLen(a, b string) int { 258 if len(a) > len(b) { 259 a, b = b, a 260 } 261 // len(a) <= len(b) 262 i := 0 263 for i < len(a) && a[i] == b[i] { 264 i++ 265 } 266 return i 267 } 268 269 func (p *exporter) qualifiedName(obj types.Object) { 270 p.string(obj.Name()) 271 p.pkg(obj.Pkg(), false) 272 } 273 274 func (p *exporter) typ(t types.Type) { 275 if t == nil { 276 log.Fatalf("gcimporter: nil type") 277 } 278 279 // Possible optimization: Anonymous pointer types *T where 280 // T is a named type are common. We could canonicalize all 281 // such types *T to a single type PT = *T. This would lead 282 // to at most one *T entry in typIndex, and all future *T's 283 // would be encoded as the respective index directly. Would 284 // save 1 byte (pointerTag) per *T and reduce the typIndex 285 // size (at the cost of a canonicalization map). We can do 286 // this later, without encoding format change. 287 288 // if we saw the type before, write its index (>= 0) 289 if i, ok := p.typIndex[t]; ok { 290 p.index('T', i) 291 return 292 } 293 294 // otherwise, remember the type, write the type tag (< 0) and type data 295 if trackAllTypes { 296 if trace { 297 p.tracef("T%d = {>\n", len(p.typIndex)) 298 defer p.tracef("<\n} ") 299 } 300 p.typIndex[t] = len(p.typIndex) 301 } 302 303 switch t := t.(type) { 304 case *types.Named: 305 if !trackAllTypes { 306 // if we don't track all types, track named types now 307 p.typIndex[t] = len(p.typIndex) 308 } 309 310 p.tag(namedTag) 311 p.pos(t.Obj()) 312 p.qualifiedName(t.Obj()) 313 p.typ(t.Underlying()) 314 if !types.IsInterface(t) { 315 p.assocMethods(t) 316 } 317 318 case *types.Array: 319 p.tag(arrayTag) 320 p.int64(t.Len()) 321 p.typ(t.Elem()) 322 323 case *types.Slice: 324 p.tag(sliceTag) 325 p.typ(t.Elem()) 326 327 case *dddSlice: 328 p.tag(dddTag) 329 p.typ(t.elem) 330 331 case *types.Struct: 332 p.tag(structTag) 333 p.fieldList(t) 334 335 case *types.Pointer: 336 p.tag(pointerTag) 337 p.typ(t.Elem()) 338 339 case *types.Signature: 340 p.tag(signatureTag) 341 p.paramList(t.Params(), t.Variadic()) 342 p.paramList(t.Results(), false) 343 344 case *types.Interface: 345 p.tag(interfaceTag) 346 p.iface(t) 347 348 case *types.Map: 349 p.tag(mapTag) 350 p.typ(t.Key()) 351 p.typ(t.Elem()) 352 353 case *types.Chan: 354 p.tag(chanTag) 355 p.int(int(3 - t.Dir())) // hack 356 p.typ(t.Elem()) 357 358 default: 359 log.Fatalf("gcimporter: unexpected type %T: %s", t, t) 360 } 361 } 362 363 func (p *exporter) assocMethods(named *types.Named) { 364 // Sort methods (for determinism). 365 var methods []*types.Func 366 for i := 0; i < named.NumMethods(); i++ { 367 methods = append(methods, named.Method(i)) 368 } 369 sort.Sort(methodsByName(methods)) 370 371 p.int(len(methods)) 372 373 if trace && methods != nil { 374 p.tracef("associated methods {>\n") 375 } 376 377 for i, m := range methods { 378 if trace && i > 0 { 379 p.tracef("\n") 380 } 381 382 p.pos(m) 383 name := m.Name() 384 p.string(name) 385 if !exported(name) { 386 p.pkg(m.Pkg(), false) 387 } 388 389 sig := m.Type().(*types.Signature) 390 p.paramList(types.NewTuple(sig.Recv()), false) 391 p.paramList(sig.Params(), sig.Variadic()) 392 p.paramList(sig.Results(), false) 393 p.int(0) // dummy value for go:nointerface pragma - ignored by importer 394 } 395 396 if trace && methods != nil { 397 p.tracef("<\n} ") 398 } 399 } 400 401 type methodsByName []*types.Func 402 403 func (x methodsByName) Len() int { return len(x) } 404 func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 405 func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } 406 407 func (p *exporter) fieldList(t *types.Struct) { 408 if trace && t.NumFields() > 0 { 409 p.tracef("fields {>\n") 410 defer p.tracef("<\n} ") 411 } 412 413 p.int(t.NumFields()) 414 for i := 0; i < t.NumFields(); i++ { 415 if trace && i > 0 { 416 p.tracef("\n") 417 } 418 p.field(t.Field(i)) 419 p.string(t.Tag(i)) 420 } 421 } 422 423 func (p *exporter) field(f *types.Var) { 424 if !f.IsField() { 425 log.Fatalf("gcimporter: field expected") 426 } 427 428 p.pos(f) 429 p.fieldName(f) 430 p.typ(f.Type()) 431 } 432 433 func (p *exporter) iface(t *types.Interface) { 434 // TODO(gri): enable importer to load embedded interfaces, 435 // then emit Embeddeds and ExplicitMethods separately here. 436 p.int(0) 437 438 n := t.NumMethods() 439 if trace && n > 0 { 440 p.tracef("methods {>\n") 441 defer p.tracef("<\n} ") 442 } 443 p.int(n) 444 for i := 0; i < n; i++ { 445 if trace && i > 0 { 446 p.tracef("\n") 447 } 448 p.method(t.Method(i)) 449 } 450 } 451 452 func (p *exporter) method(m *types.Func) { 453 sig := m.Type().(*types.Signature) 454 if sig.Recv() == nil { 455 log.Fatalf("gcimporter: method expected") 456 } 457 458 p.pos(m) 459 p.string(m.Name()) 460 if m.Name() != "_" && !ast.IsExported(m.Name()) { 461 p.pkg(m.Pkg(), false) 462 } 463 464 // interface method; no need to encode receiver. 465 p.paramList(sig.Params(), sig.Variadic()) 466 p.paramList(sig.Results(), false) 467 } 468 469 func (p *exporter) fieldName(f *types.Var) { 470 name := f.Name() 471 472 if f.Anonymous() { 473 // anonymous field - we distinguish between 3 cases: 474 // 1) field name matches base type name and is exported 475 // 2) field name matches base type name and is not exported 476 // 3) field name doesn't match base type name (alias name) 477 bname := basetypeName(f.Type()) 478 if name == bname { 479 if ast.IsExported(name) { 480 name = "" // 1) we don't need to know the field name or package 481 } else { 482 name = "?" // 2) use unexported name "?" to force package export 483 } 484 } else { 485 // 3) indicate alias and export name as is 486 // (this requires an extra "@" but this is a rare case) 487 p.string("@") 488 } 489 } 490 491 p.string(name) 492 if name != "" && !ast.IsExported(name) { 493 p.pkg(f.Pkg(), false) 494 } 495 } 496 497 func basetypeName(typ types.Type) string { 498 switch typ := deref(typ).(type) { 499 case *types.Basic: 500 return typ.Name() 501 case *types.Named: 502 return typ.Obj().Name() 503 default: 504 return "" // unnamed type 505 } 506 } 507 508 func (p *exporter) paramList(params *types.Tuple, variadic bool) { 509 // use negative length to indicate unnamed parameters 510 // (look at the first parameter only since either all 511 // names are present or all are absent) 512 n := params.Len() 513 if n > 0 && params.At(0).Name() == "" { 514 n = -n 515 } 516 p.int(n) 517 for i := 0; i < params.Len(); i++ { 518 q := params.At(i) 519 t := q.Type() 520 if variadic && i == params.Len()-1 { 521 t = &dddSlice{t.(*types.Slice).Elem()} 522 } 523 p.typ(t) 524 if n > 0 { 525 name := q.Name() 526 p.string(name) 527 if name != "_" { 528 p.pkg(q.Pkg(), false) 529 } 530 } 531 p.string("") // no compiler-specific info 532 } 533 } 534 535 func (p *exporter) value(x constant.Value) { 536 if trace { 537 p.tracef("= ") 538 } 539 540 switch x.Kind() { 541 case constant.Bool: 542 tag := falseTag 543 if constant.BoolVal(x) { 544 tag = trueTag 545 } 546 p.tag(tag) 547 548 case constant.Int: 549 if v, exact := constant.Int64Val(x); exact { 550 // common case: x fits into an int64 - use compact encoding 551 p.tag(int64Tag) 552 p.int64(v) 553 return 554 } 555 // uncommon case: large x - use float encoding 556 // (powers of 2 will be encoded efficiently with exponent) 557 p.tag(floatTag) 558 p.float(constant.ToFloat(x)) 559 560 case constant.Float: 561 p.tag(floatTag) 562 p.float(x) 563 564 case constant.Complex: 565 p.tag(complexTag) 566 p.float(constant.Real(x)) 567 p.float(constant.Imag(x)) 568 569 case constant.String: 570 p.tag(stringTag) 571 p.string(constant.StringVal(x)) 572 573 case constant.Unknown: 574 // package contains type errors 575 p.tag(unknownTag) 576 577 default: 578 log.Fatalf("gcimporter: unexpected value %v (%T)", x, x) 579 } 580 } 581 582 func (p *exporter) float(x constant.Value) { 583 if x.Kind() != constant.Float { 584 log.Fatalf("gcimporter: unexpected constant %v, want float", x) 585 } 586 // extract sign (there is no -0) 587 sign := constant.Sign(x) 588 if sign == 0 { 589 // x == 0 590 p.int(0) 591 return 592 } 593 // x != 0 594 595 var f big.Float 596 if v, exact := constant.Float64Val(x); exact { 597 // float64 598 f.SetFloat64(v) 599 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 600 // TODO(gri): add big.Rat accessor to constant.Value. 601 r := valueToRat(num) 602 f.SetRat(r.Quo(r, valueToRat(denom))) 603 } else { 604 // Value too large to represent as a fraction => inaccessible. 605 // TODO(gri): add big.Float accessor to constant.Value. 606 f.SetFloat64(math.MaxFloat64) // FIXME 607 } 608 609 // extract exponent such that 0.5 <= m < 1.0 610 var m big.Float 611 exp := f.MantExp(&m) 612 613 // extract mantissa as *big.Int 614 // - set exponent large enough so mant satisfies mant.IsInt() 615 // - get *big.Int from mant 616 m.SetMantExp(&m, int(m.MinPrec())) 617 mant, acc := m.Int(nil) 618 if acc != big.Exact { 619 log.Fatalf("gcimporter: internal error") 620 } 621 622 p.int(sign) 623 p.int(exp) 624 p.string(string(mant.Bytes())) 625 } 626 627 func valueToRat(x constant.Value) *big.Rat { 628 // Convert little-endian to big-endian. 629 // I can't believe this is necessary. 630 bytes := constant.Bytes(x) 631 for i := 0; i < len(bytes)/2; i++ { 632 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] 633 } 634 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) 635 } 636 637 func (p *exporter) bool(b bool) bool { 638 if trace { 639 p.tracef("[") 640 defer p.tracef("= %v] ", b) 641 } 642 643 x := 0 644 if b { 645 x = 1 646 } 647 p.int(x) 648 return b 649 } 650 651 // ---------------------------------------------------------------------------- 652 // Low-level encoders 653 654 func (p *exporter) index(marker byte, index int) { 655 if index < 0 { 656 log.Fatalf("gcimporter: invalid index < 0") 657 } 658 if debugFormat { 659 p.marker('t') 660 } 661 if trace { 662 p.tracef("%c%d ", marker, index) 663 } 664 p.rawInt64(int64(index)) 665 } 666 667 func (p *exporter) tag(tag int) { 668 if tag >= 0 { 669 log.Fatalf("gcimporter: invalid tag >= 0") 670 } 671 if debugFormat { 672 p.marker('t') 673 } 674 if trace { 675 p.tracef("%s ", tagString[-tag]) 676 } 677 p.rawInt64(int64(tag)) 678 } 679 680 func (p *exporter) int(x int) { 681 p.int64(int64(x)) 682 } 683 684 func (p *exporter) int64(x int64) { 685 if debugFormat { 686 p.marker('i') 687 } 688 if trace { 689 p.tracef("%d ", x) 690 } 691 p.rawInt64(x) 692 } 693 694 func (p *exporter) string(s string) { 695 if debugFormat { 696 p.marker('s') 697 } 698 if trace { 699 p.tracef("%q ", s) 700 } 701 // if we saw the string before, write its index (>= 0) 702 // (the empty string is mapped to 0) 703 if i, ok := p.strIndex[s]; ok { 704 p.rawInt64(int64(i)) 705 return 706 } 707 // otherwise, remember string and write its negative length and bytes 708 p.strIndex[s] = len(p.strIndex) 709 p.rawInt64(-int64(len(s))) 710 for i := 0; i < len(s); i++ { 711 p.rawByte(s[i]) 712 } 713 } 714 715 // marker emits a marker byte and position information which makes 716 // it easy for a reader to detect if it is "out of sync". Used for 717 // debugFormat format only. 718 func (p *exporter) marker(m byte) { 719 p.rawByte(m) 720 // Enable this for help tracking down the location 721 // of an incorrect marker when running in debugFormat. 722 if false && trace { 723 p.tracef("#%d ", p.written) 724 } 725 p.rawInt64(int64(p.written)) 726 } 727 728 // rawInt64 should only be used by low-level encoders. 729 func (p *exporter) rawInt64(x int64) { 730 var tmp [binary.MaxVarintLen64]byte 731 n := binary.PutVarint(tmp[:], x) 732 for i := 0; i < n; i++ { 733 p.rawByte(tmp[i]) 734 } 735 } 736 737 // rawStringln should only be used to emit the initial version string. 738 func (p *exporter) rawStringln(s string) { 739 for i := 0; i < len(s); i++ { 740 p.rawByte(s[i]) 741 } 742 p.rawByte('\n') 743 } 744 745 // rawByte is the bottleneck interface to write to p.out. 746 // rawByte escapes b as follows (any encoding does that 747 // hides '$'): 748 // 749 // '$' => '|' 'S' 750 // '|' => '|' '|' 751 // 752 // Necessary so other tools can find the end of the 753 // export data by searching for "$$". 754 // rawByte should only be used by low-level encoders. 755 func (p *exporter) rawByte(b byte) { 756 switch b { 757 case '$': 758 // write '$' as '|' 'S' 759 b = 'S' 760 fallthrough 761 case '|': 762 // write '|' as '|' '|' 763 p.out.WriteByte('|') 764 p.written++ 765 } 766 p.out.WriteByte(b) 767 p.written++ 768 } 769 770 // tracef is like fmt.Printf but it rewrites the format string 771 // to take care of indentation. 772 func (p *exporter) tracef(format string, args ...interface{}) { 773 if strings.ContainsAny(format, "<>\n") { 774 var buf bytes.Buffer 775 for i := 0; i < len(format); i++ { 776 // no need to deal with runes 777 ch := format[i] 778 switch ch { 779 case '>': 780 p.indent++ 781 continue 782 case '<': 783 p.indent-- 784 continue 785 } 786 buf.WriteByte(ch) 787 if ch == '\n' { 788 for j := p.indent; j > 0; j-- { 789 buf.WriteString(". ") 790 } 791 } 792 } 793 format = buf.String() 794 } 795 fmt.Printf(format, args...) 796 } 797 798 // Debugging support. 799 // (tagString is only used when tracing is enabled) 800 var tagString = [...]string{ 801 // Packages 802 -packageTag: "package", 803 804 // Types 805 -namedTag: "named type", 806 -arrayTag: "array", 807 -sliceTag: "slice", 808 -dddTag: "ddd", 809 -structTag: "struct", 810 -pointerTag: "pointer", 811 -signatureTag: "signature", 812 -interfaceTag: "interface", 813 -mapTag: "map", 814 -chanTag: "chan", 815 816 // Values 817 -falseTag: "false", 818 -trueTag: "true", 819 -int64Tag: "int64", 820 -floatTag: "float", 821 -fractionTag: "fraction", 822 -complexTag: "complex", 823 -stringTag: "string", 824 -unknownTag: "unknown", 825 826 // Type aliases 827 -aliasTag: "alias", 828 }