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 5package types2 6 7import ( 8 "cmd/compile/internal/syntax" 9 "fmt" 10 "go/constant" 11 "sort" 12 "strconv" 13 "strings" 14 "unicode" 15) 16 17// A declInfo describes a package-level const, type, var, or func declaration. 18type declInfo struct { 19 file *Scope // scope of file containing this declaration 20 lhs []*Var // lhs of n:1 variable declarations, or nil 21 vtyp syntax.Expr // type, or nil (for const and var declarations only) 22 init syntax.Expr // init/orig expression, or nil (for const and var declarations only) 23 inherited bool // if set, the init expression is inherited from a previous constant declaration 24 tdecl *syntax.TypeDecl // type declaration, or nil 25 fdecl *syntax.FuncDecl // func declaration, or nil 26 27 // The deps field tracks initialization expression dependencies. 28 deps map[Object]bool // lazily initialized 29} 30 31// hasInitializer reports whether the declared object has an initialization 32// expression or function body. 33func (d *declInfo) hasInitializer() bool { 34 return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil 35} 36 37// addDep adds obj to the set of objects d's init expression depends on. 38func (d *declInfo) addDep(obj Object) { 39 m := d.deps 40 if m == nil { 41 m = make(map[Object]bool) 42 d.deps = m 43 } 44 m[obj] = true 45} 46 47// arity checks that the lhs and rhs of a const or var decl 48// have a matching number of names and initialization values. 49// If inherited is set, the initialization values are from 50// another (constant) declaration. 51func (check *Checker) arity(pos syntax.Pos, names []*syntax.Name, inits []syntax.Expr, constDecl, inherited bool) { 52 l := len(names) 53 r := len(inits) 54 55 switch { 56 case l < r: 57 n := inits[l] 58 if inherited { 59 check.errorf(pos, "extra init expr at %s", n.Pos()) 60 } else { 61 check.errorf(n, "extra init expr %s", n) 62 } 63 case l > r && (constDecl || r != 1): // if r == 1 it may be a multi-valued function and we can't say anything yet 64 n := names[r] 65 check.errorf(n, "missing init expr for %s", n.Value) 66 } 67} 68 69func validatedImportPath(path string) (string, error) { 70 s, err := strconv.Unquote(path) 71 if err != nil { 72 return "", err 73 } 74 if s == "" { 75 return "", fmt.Errorf("empty string") 76 } 77 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" 78 for _, r := range s { 79 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { 80 return s, fmt.Errorf("invalid character %#U", r) 81 } 82 } 83 return s, nil 84} 85 86// declarePkgObj declares obj in the package scope, records its ident -> obj mapping, 87// and updates check.objMap. The object must not be a function or method. 88func (check *Checker) declarePkgObj(ident *syntax.Name, obj Object, d *declInfo) { 89 assert(ident.Value == obj.Name()) 90 91 // spec: "A package-scope or file-scope identifier with name init 92 // may only be declared to be a function with this (func()) signature." 93 if ident.Value == "init" { 94 check.error(ident, "cannot declare init - must be func") 95 return 96 } 97 98 // spec: "The main package must have package name main and declare 99 // a function main that takes no arguments and returns no value." 100 if ident.Value == "main" && check.pkg.name == "main" { 101 check.error(ident, "cannot declare main - must be func") 102 return 103 } 104 105 check.declare(check.pkg.scope, ident, obj, nopos) 106 check.objMap[obj] = d 107 obj.setOrder(uint32(len(check.objMap))) 108} 109 110// filename returns a filename suitable for debugging output. 111func (check *Checker) filename(fileNo int) string { 112 file := check.files[fileNo] 113 if pos := file.Pos(); pos.IsKnown() { 114 // return check.fset.File(pos).Name() 115 // TODO(gri) do we need the actual file name here? 116 return pos.RelFilename() 117 } 118 return fmt.Sprintf("file[%d]", fileNo) 119} 120 121func (check *Checker) importPackage(pos syntax.Pos, path, dir string) *Package { 122 // If we already have a package for the given (path, dir) 123 // pair, use it instead of doing a full import. 124 // Checker.impMap only caches packages that are marked Complete 125 // or fake (dummy packages for failed imports). Incomplete but 126 // non-fake packages do require an import to complete them. 127 key := importKey{path, dir} 128 imp := check.impMap[key] 129 if imp != nil { 130 return imp 131 } 132 133 // no package yet => import it 134 if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) { 135 imp = NewPackage("C", "C") 136 imp.fake = true // package scope is not populated 137 imp.cgo = check.conf.go115UsesCgo 138 } else { 139 // ordinary import 140 var err error 141 if importer := check.conf.Importer; importer == nil { 142 err = fmt.Errorf("Config.Importer not installed") 143 } else if importerFrom, ok := importer.(ImporterFrom); ok { 144 imp, err = importerFrom.ImportFrom(path, dir, 0) 145 if imp == nil && err == nil { 146 err = fmt.Errorf("Config.Importer.ImportFrom(%s, %s, 0) returned nil but no error", path, dir) 147 } 148 } else { 149 imp, err = importer.Import(path) 150 if imp == nil && err == nil { 151 err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path) 152 } 153 } 154 // make sure we have a valid package name 155 // (errors here can only happen through manipulation of packages after creation) 156 if err == nil && imp != nil && (imp.name == "_" || imp.name == "") { 157 err = fmt.Errorf("invalid package name: %q", imp.name) 158 imp = nil // create fake package below 159 } 160 if err != nil { 161 check.errorf(pos, "could not import %s (%s)", path, err) 162 if imp == nil { 163 // create a new fake package 164 // come up with a sensible package name (heuristic) 165 name := path 166 if i := len(name); i > 0 && name[i-1] == '/' { 167 name = name[:i-1] 168 } 169 if i := strings.LastIndex(name, "/"); i >= 0 { 170 name = name[i+1:] 171 } 172 imp = NewPackage(path, name) 173 } 174 // continue to use the package as best as we can 175 imp.fake = true // avoid follow-up lookup failures 176 } 177 } 178 179 // package should be complete or marked fake, but be cautious 180 if imp.complete || imp.fake { 181 check.impMap[key] = imp 182 // Once we've formatted an error message once, keep the pkgPathMap 183 // up-to-date on subsequent imports. 184 if check.pkgPathMap != nil { 185 check.markImports(imp) 186 } 187 return imp 188 } 189 190 // something went wrong (importer may have returned incomplete package without error) 191 return nil 192} 193 194// collectObjects collects all file and package objects and inserts them 195// into their respective scopes. It also performs imports and associates 196// methods with receiver base type names. 197func (check *Checker) collectObjects() { 198 pkg := check.pkg 199 pkg.height = 0 200 201 // pkgImports is the set of packages already imported by any package file seen 202 // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate 203 // it (pkg.imports may not be empty if we are checking test files incrementally). 204 // Note that pkgImports is keyed by package (and thus package path), not by an 205 // importKey value. Two different importKey values may map to the same package 206 // which is why we cannot use the check.impMap here. 207 var pkgImports = make(map[*Package]bool) 208 for _, imp := range pkg.imports { 209 pkgImports[imp] = true 210 } 211 212 type methodInfo struct { 213 obj *Func // method 214 ptr bool // true if pointer receiver 215 recv *syntax.Name // receiver type name 216 } 217 var methods []methodInfo // collected methods with valid receivers and non-blank _ names 218 var fileScopes []*Scope 219 for fileNo, file := range check.files { 220 // The package identifier denotes the current package, 221 // but there is no corresponding package object. 222 check.recordDef(file.PkgName, nil) 223 224 fileScope := NewScope(check.pkg.scope, syntax.StartPos(file), syntax.EndPos(file), check.filename(fileNo)) 225 fileScopes = append(fileScopes, fileScope) 226 check.recordScope(file, fileScope) 227 228 // determine file directory, necessary to resolve imports 229 // FileName may be "" (typically for tests) in which case 230 // we get "." as the directory which is what we would want. 231 fileDir := dir(file.PkgName.Pos().RelFilename()) // TODO(gri) should this be filename? 232 233 first := -1 // index of first ConstDecl in the current group, or -1 234 var last *syntax.ConstDecl // last ConstDecl with init expressions, or nil 235 for index, decl := range file.DeclList { 236 if _, ok := decl.(*syntax.ConstDecl); !ok { 237 first = -1 // we're not in a constant declaration 238 } 239 240 switch s := decl.(type) { 241 case *syntax.ImportDecl: 242 // import package 243 if s.Path == nil || s.Path.Bad { 244 continue // error reported during parsing 245 } 246 path, err := validatedImportPath(s.Path.Value) 247 if err != nil { 248 check.errorf(s.Path, "invalid import path (%s)", err) 249 continue 250 } 251 252 imp := check.importPackage(s.Path.Pos(), path, fileDir) 253 if imp == nil { 254 continue 255 } 256 257 if imp == Unsafe { 258 // typecheck ignores imports of package unsafe for 259 // calculating height. 260 // TODO(mdempsky): Revisit this. This seems fine, but I 261 // don't remember explicitly considering this case. 262 } else if h := imp.height + 1; h > pkg.height { 263 pkg.height = h 264 } 265 266 // local name overrides imported package name 267 name := imp.name 268 if s.LocalPkgName != nil { 269 name = s.LocalPkgName.Value 270 if path == "C" { 271 // match cmd/compile (not prescribed by spec) 272 check.error(s.LocalPkgName, `cannot rename import "C"`) 273 continue 274 } 275 } 276 277 if name == "init" { 278 check.error(s, "cannot import package as init - init must be a func") 279 continue 280 } 281 282 // add package to list of explicit imports 283 // (this functionality is provided as a convenience 284 // for clients; it is not needed for type-checking) 285 if !pkgImports[imp] { 286 pkgImports[imp] = true 287 pkg.imports = append(pkg.imports, imp) 288 } 289 290 pkgName := NewPkgName(s.Pos(), pkg, name, imp) 291 if s.LocalPkgName != nil { 292 // in a dot-import, the dot represents the package 293 check.recordDef(s.LocalPkgName, pkgName) 294 } else { 295 check.recordImplicit(s, pkgName) 296 } 297 298 if path == "C" { 299 // match cmd/compile (not prescribed by spec) 300 pkgName.used = true 301 } 302 303 // add import to file scope 304 check.imports = append(check.imports, pkgName) 305 if name == "." { 306 // dot-import 307 if check.dotImportMap == nil { 308 check.dotImportMap = make(map[dotImportKey]*PkgName) 309 } 310 // merge imported scope with file scope 311 for name, obj := range imp.scope.elems { 312 // Note: Avoid eager resolve(name, obj) here, so we only 313 // resolve dot-imported objects as needed. 314 315 // A package scope may contain non-exported objects, 316 // do not import them! 317 if isExported(name) { 318 // declare dot-imported object 319 // (Do not use check.declare because it modifies the object 320 // via Object.setScopePos, which leads to a race condition; 321 // the object may be imported into more than one file scope 322 // concurrently. See issue #32154.) 323 if alt := fileScope.Lookup(name); alt != nil { 324 var err error_ 325 err.errorf(s.LocalPkgName, "%s redeclared in this block", alt.Name()) 326 err.recordAltDecl(alt) 327 check.report(&err) 328 } else { 329 fileScope.insert(name, obj) 330 check.dotImportMap[dotImportKey{fileScope, name}] = pkgName 331 } 332 } 333 } 334 } else { 335 // declare imported package object in file scope 336 // (no need to provide s.LocalPkgName since we called check.recordDef earlier) 337 check.declare(fileScope, nil, pkgName, nopos) 338 } 339 340 case *syntax.ConstDecl: 341 // iota is the index of the current constDecl within the group 342 if first < 0 || file.DeclList[index-1].(*syntax.ConstDecl).Group != s.Group { 343 first = index 344 last = nil 345 } 346 iota := constant.MakeInt64(int64(index - first)) 347 348 // determine which initialization expressions to use 349 inherited := true 350 switch { 351 case s.Type != nil || s.Values != nil: 352 last = s 353 inherited = false 354 case last == nil: 355 last = new(syntax.ConstDecl) // make sure last exists 356 inherited = false 357 } 358 359 // declare all constants 360 values := unpackExpr(last.Values) 361 for i, name := range s.NameList { 362 obj := NewConst(name.Pos(), pkg, name.Value, nil, iota) 363 364 var init syntax.Expr 365 if i < len(values) { 366 init = values[i] 367 } 368 369 d := &declInfo{file: fileScope, vtyp: last.Type, init: init, inherited: inherited} 370 check.declarePkgObj(name, obj, d) 371 } 372 373 // Constants must always have init values. 374 check.arity(s.Pos(), s.NameList, values, true, inherited) 375 376 case *syntax.VarDecl: 377 lhs := make([]*Var, len(s.NameList)) 378 // If there's exactly one rhs initializer, use 379 // the same declInfo d1 for all lhs variables 380 // so that each lhs variable depends on the same 381 // rhs initializer (n:1 var declaration). 382 var d1 *declInfo 383 if _, ok := s.Values.(*syntax.ListExpr); !ok { 384 // The lhs elements are only set up after the for loop below, 385 // but that's ok because declarePkgObj only collects the declInfo 386 // for a later phase. 387 d1 = &declInfo{file: fileScope, lhs: lhs, vtyp: s.Type, init: s.Values} 388 } 389 390 // declare all variables 391 values := unpackExpr(s.Values) 392 for i, name := range s.NameList { 393 obj := NewVar(name.Pos(), pkg, name.Value, nil) 394 lhs[i] = obj 395 396 d := d1 397 if d == nil { 398 // individual assignments 399 var init syntax.Expr 400 if i < len(values) { 401 init = values[i] 402 } 403 d = &declInfo{file: fileScope, vtyp: s.Type, init: init} 404 } 405 406 check.declarePkgObj(name, obj, d) 407 } 408 409 // If we have no type, we must have values. 410 if s.Type == nil || values != nil { 411 check.arity(s.Pos(), s.NameList, values, false, false) 412 } 413 414 case *syntax.TypeDecl: 415 if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) { 416 check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") 417 } 418 obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil) 419 check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s}) 420 421 case *syntax.FuncDecl: 422 name := s.Name.Value 423 obj := NewFunc(s.Name.Pos(), pkg, name, nil) 424 hasTParamError := false // avoid duplicate type parameter errors 425 if s.Recv == nil { 426 // regular function 427 if name == "init" || name == "main" && pkg.name == "main" { 428 if len(s.TParamList) != 0 { 429 check.softErrorf(s.TParamList[0], "func %s must have no type parameters", name) 430 hasTParamError = true 431 } 432 if t := s.Type; len(t.ParamList) != 0 || len(t.ResultList) != 0 { 433 check.softErrorf(s, "func %s must have no arguments and no return values", name) 434 } 435 } 436 // don't declare init functions in the package scope - they are invisible 437 if name == "init" { 438 obj.parent = pkg.scope 439 check.recordDef(s.Name, obj) 440 // init functions must have a body 441 if s.Body == nil { 442 // TODO(gri) make this error message consistent with the others above 443 check.softErrorf(obj.pos, "missing function body") 444 } 445 } else { 446 check.declare(pkg.scope, s.Name, obj, nopos) 447 } 448 } else { 449 // method 450 // d.Recv != nil 451 if !acceptMethodTypeParams && len(s.TParamList) != 0 { 452 //check.error(d.TParamList.Pos(), invalidAST + "method must have no type parameters") 453 check.error(s.TParamList[0], invalidAST+"method must have no type parameters") 454 hasTParamError = true 455 } 456 ptr, recv, _ := check.unpackRecv(s.Recv.Type, false) 457 // (Methods with invalid receiver cannot be associated to a type, and 458 // methods with blank _ names are never found; no need to collect any 459 // of them. They will still be type-checked with all the other functions.) 460 if recv != nil && name != "_" { 461 methods = append(methods, methodInfo{obj, ptr, recv}) 462 } 463 check.recordDef(s.Name, obj) 464 } 465 if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError { 466 check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") 467 } 468 info := &declInfo{file: fileScope, fdecl: s} 469 // Methods are not package-level objects but we still track them in the 470 // object map so that we can handle them like regular functions (if the 471 // receiver is invalid); also we need their fdecl info when associating 472 // them with their receiver base type, below. 473 check.objMap[obj] = info 474 obj.setOrder(uint32(len(check.objMap))) 475 476 default: 477 check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s) 478 } 479 } 480 } 481 482 // verify that objects in package and file scopes have different names 483 for _, scope := range fileScopes { 484 for name, obj := range scope.elems { 485 if alt := pkg.scope.Lookup(name); alt != nil { 486 obj = resolve(name, obj) 487 var err error_ 488 if pkg, ok := obj.(*PkgName); ok { 489 err.errorf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported()) 490 err.recordAltDecl(pkg) 491 } else { 492 err.errorf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) 493 // TODO(gri) dot-imported objects don't have a position; recordAltDecl won't print anything 494 err.recordAltDecl(obj) 495 } 496 check.report(&err) 497 } 498 } 499 } 500 501 // Now that we have all package scope objects and all methods, 502 // associate methods with receiver base type name where possible. 503 // Ignore methods that have an invalid receiver. They will be 504 // type-checked later, with regular functions. 505 if methods != nil { 506 check.methods = make(map[*TypeName][]*Func) 507 for i := range methods { 508 m := &methods[i] 509 // Determine the receiver base type and associate m with it. 510 ptr, base := check.resolveBaseTypeName(m.ptr, m.recv) 511 if base != nil { 512 m.obj.hasPtrRecv_ = ptr 513 check.methods[base] = append(check.methods[base], m.obj) 514 } 515 } 516 } 517} 518 519// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether 520// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its 521// type parameters, if any. The type parameters are only unpacked if unpackParams is 522// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we 523// cannot easily work around). 524func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, rname *syntax.Name, tparams []*syntax.Name) { 525L: // unpack receiver type 526 // This accepts invalid receivers such as ***T and does not 527 // work for other invalid receivers, but we don't care. The 528 // validity of receiver expressions is checked elsewhere. 529 for { 530 switch t := rtyp.(type) { 531 case *syntax.ParenExpr: 532 rtyp = t.X 533 // case *ast.StarExpr: 534 // ptr = true 535 // rtyp = t.X 536 case *syntax.Operation: 537 if t.Op != syntax.Mul || t.Y != nil { 538 break 539 } 540 ptr = true 541 rtyp = t.X 542 default: 543 break L 544 } 545 } 546 547 // unpack type parameters, if any 548 if ptyp, _ := rtyp.(*syntax.IndexExpr); ptyp != nil { 549 rtyp = ptyp.X 550 if unpackParams { 551 for _, arg := range unpackExpr(ptyp.Index) { 552 var par *syntax.Name 553 switch arg := arg.(type) { 554 case *syntax.Name: 555 par = arg 556 case *syntax.BadExpr: 557 // ignore - error already reported by parser 558 case nil: 559 check.error(ptyp, invalidAST+"parameterized receiver contains nil parameters") 560 default: 561 check.errorf(arg, "receiver type parameter %s must be an identifier", arg) 562 } 563 if par == nil { 564 par = syntax.NewName(arg.Pos(), "_") 565 } 566 tparams = append(tparams, par) 567 } 568 569 } 570 } 571 572 // unpack receiver name 573 if name, _ := rtyp.(*syntax.Name); name != nil { 574 rname = name 575 } 576 577 return 578} 579 580// resolveBaseTypeName returns the non-alias base type name for typ, and whether 581// there was a pointer indirection to get to it. The base type name must be declared 582// in package scope, and there can be at most one pointer indirection. If no such type 583// name exists, the returned base is nil. 584func (check *Checker) resolveBaseTypeName(seenPtr bool, typ syntax.Expr) (ptr bool, base *TypeName) { 585 // Algorithm: Starting from a type expression, which may be a name, 586 // we follow that type through alias declarations until we reach a 587 // non-alias type name. If we encounter anything but pointer types or 588 // parentheses we're done. If we encounter more than one pointer type 589 // we're done. 590 ptr = seenPtr 591 var seen map[*TypeName]bool 592 for { 593 typ = unparen(typ) 594 595 // check if we have a pointer type 596 // if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil { 597 if pexpr, _ := typ.(*syntax.Operation); pexpr != nil && pexpr.Op == syntax.Mul && pexpr.Y == nil { 598 // if we've already seen a pointer, we're done 599 if ptr { 600 return false, nil 601 } 602 ptr = true 603 typ = unparen(pexpr.X) // continue with pointer base type 604 } 605 606 // typ must be a name 607 name, _ := typ.(*syntax.Name) 608 if name == nil { 609 return false, nil 610 } 611 612 // name must denote an object found in the current package scope 613 // (note that dot-imported objects are not in the package scope!) 614 obj := check.pkg.scope.Lookup(name.Value) 615 if obj == nil { 616 return false, nil 617 } 618 619 // the object must be a type name... 620 tname, _ := obj.(*TypeName) 621 if tname == nil { 622 return false, nil 623 } 624 625 // ... which we have not seen before 626 if seen[tname] { 627 return false, nil 628 } 629 630 // we're done if tdecl defined tname as a new type 631 // (rather than an alias) 632 tdecl := check.objMap[tname].tdecl // must exist for objects in package scope 633 if !tdecl.Alias { 634 return ptr, tname 635 } 636 637 // otherwise, continue resolving 638 typ = tdecl.Type 639 if seen == nil { 640 seen = make(map[*TypeName]bool) 641 } 642 seen[tname] = true 643 } 644} 645 646// packageObjects typechecks all package objects, but not function bodies. 647func (check *Checker) packageObjects() { 648 // process package objects in source order for reproducible results 649 objList := make([]Object, len(check.objMap)) 650 i := 0 651 for obj := range check.objMap { 652 objList[i] = obj 653 i++ 654 } 655 sort.Sort(inSourceOrder(objList)) 656 657 // add new methods to already type-checked types (from a prior Checker.Files call) 658 for _, obj := range objList { 659 if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil { 660 check.collectMethods(obj) 661 } 662 } 663 664 // We process non-alias declarations first, in order to avoid situations where 665 // the type of an alias declaration is needed before it is available. In general 666 // this is still not enough, as it is possible to create sufficiently convoluted 667 // recursive type definitions that will cause a type alias to be needed before it 668 // is available (see issue #25838 for examples). 669 // As an aside, the cmd/compiler suffers from the same problem (#25838). 670 var aliasList []*TypeName 671 // phase 1 672 for _, obj := range objList { 673 // If we have a type alias, collect it for the 2nd phase. 674 if tname, _ := obj.(*TypeName); tname != nil && check.objMap[tname].tdecl.Alias { 675 aliasList = append(aliasList, tname) 676 continue 677 } 678 679 check.objDecl(obj, nil) 680 } 681 // phase 2 682 for _, obj := range aliasList { 683 check.objDecl(obj, nil) 684 } 685 686 // At this point we may have a non-empty check.methods map; this means that not all 687 // entries were deleted at the end of typeDecl because the respective receiver base 688 // types were not found. In that case, an error was reported when declaring those 689 // methods. We can now safely discard this map. 690 check.methods = nil 691} 692 693// inSourceOrder implements the sort.Sort interface. 694type inSourceOrder []Object 695 696func (a inSourceOrder) Len() int { return len(a) } 697func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() } 698func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 699 700// unusedImports checks for unused imports. 701func (check *Checker) unusedImports() { 702 // if function bodies are not checked, packages' uses are likely missing - don't check 703 if check.conf.IgnoreFuncBodies { 704 return 705 } 706 707 // spec: "It is illegal (...) to directly import a package without referring to 708 // any of its exported identifiers. To import a package solely for its side-effects 709 // (initialization), use the blank identifier as explicit package name." 710 711 for _, obj := range check.imports { 712 if !obj.used && obj.name != "_" { 713 check.errorUnusedPkg(obj) 714 } 715 } 716} 717 718func (check *Checker) errorUnusedPkg(obj *PkgName) { 719 // If the package was imported with a name other than the final 720 // import path element, show it explicitly in the error message. 721 // Note that this handles both renamed imports and imports of 722 // packages containing unconventional package declarations. 723 // Note that this uses / always, even on Windows, because Go import 724 // paths always use forward slashes. 725 path := obj.imported.path 726 elem := path 727 if i := strings.LastIndex(elem, "/"); i >= 0 { 728 elem = elem[i+1:] 729 } 730 if obj.name == "" || obj.name == "." || obj.name == elem { 731 if check.conf.CompilerErrorMessages { 732 check.softErrorf(obj, "imported and not used: %q", path) 733 } else { 734 check.softErrorf(obj, "%q imported but not used", path) 735 } 736 } else { 737 if check.conf.CompilerErrorMessages { 738 check.softErrorf(obj, "imported and not used: %q as %s", path, obj.name) 739 } else { 740 check.softErrorf(obj, "%q imported but not used as %s", path, obj.name) 741 } 742 } 743} 744 745// dir makes a good-faith attempt to return the directory 746// portion of path. If path is empty, the result is ".". 747// (Per the go/build package dependency tests, we cannot import 748// path/filepath and simply use filepath.Dir.) 749func dir(path string) string { 750 if i := strings.LastIndexAny(path, `/\`); i > 0 { 751 return path[:i] 752 } 753 // i <= 0 754 return "." 755} 756