1
2
3
4
5 package noder
6
7 import (
8 "errors"
9 "fmt"
10 "internal/buildcfg"
11 "io"
12 "os"
13 pathpkg "path"
14 "runtime"
15 "sort"
16 "strconv"
17 "strings"
18 "unicode"
19 "unicode/utf8"
20
21 "cmd/compile/internal/base"
22 "cmd/compile/internal/importer"
23 "cmd/compile/internal/ir"
24 "cmd/compile/internal/syntax"
25 "cmd/compile/internal/typecheck"
26 "cmd/compile/internal/types"
27 "cmd/compile/internal/types2"
28 "cmd/internal/archive"
29 "cmd/internal/bio"
30 "cmd/internal/goobj"
31 "cmd/internal/objabi"
32 "cmd/internal/src"
33 )
34
35
36 type gcimports struct {
37 packages map[string]*types2.Package
38 }
39
40 func (m *gcimports) Import(path string) (*types2.Package, error) {
41 return m.ImportFrom(path, "" , 0)
42 }
43
44 func (m *gcimports) ImportFrom(path, srcDir string, mode types2.ImportMode) (*types2.Package, error) {
45 if mode != 0 {
46 panic("mode must be 0")
47 }
48
49 path, err := resolveImportPath(path)
50 if err != nil {
51 return nil, err
52 }
53
54 lookup := func(path string) (io.ReadCloser, error) { return openPackage(path) }
55 return importer.Import(m.packages, path, srcDir, lookup)
56 }
57
58 func isDriveLetter(b byte) bool {
59 return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
60 }
61
62
63 func islocalname(name string) bool {
64 return strings.HasPrefix(name, "/") ||
65 runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
66 strings.HasPrefix(name, "./") || name == "." ||
67 strings.HasPrefix(name, "../") || name == ".."
68 }
69
70 func openPackage(path string) (*os.File, error) {
71 if islocalname(path) {
72 if base.Flag.NoLocalImports {
73 return nil, errors.New("local imports disallowed")
74 }
75
76 if base.Flag.Cfg.PackageFile != nil {
77 return os.Open(base.Flag.Cfg.PackageFile[path])
78 }
79
80
81
82
83 if file, err := os.Open(fmt.Sprintf("%s.a", path)); err == nil {
84 return file, nil
85 }
86 if file, err := os.Open(fmt.Sprintf("%s.o", path)); err == nil {
87 return file, nil
88 }
89 return nil, errors.New("file not found")
90 }
91
92
93
94
95 if q := pathpkg.Clean(path); q != path {
96 return nil, fmt.Errorf("non-canonical import path %q (should be %q)", path, q)
97 }
98
99 if base.Flag.Cfg.PackageFile != nil {
100 return os.Open(base.Flag.Cfg.PackageFile[path])
101 }
102
103 for _, dir := range base.Flag.Cfg.ImportDirs {
104 if file, err := os.Open(fmt.Sprintf("%s/%s.a", dir, path)); err == nil {
105 return file, nil
106 }
107 if file, err := os.Open(fmt.Sprintf("%s/%s.o", dir, path)); err == nil {
108 return file, nil
109 }
110 }
111
112 if buildcfg.GOROOT != "" {
113 suffix := ""
114 if base.Flag.InstallSuffix != "" {
115 suffix = "_" + base.Flag.InstallSuffix
116 } else if base.Flag.Race {
117 suffix = "_race"
118 } else if base.Flag.MSan {
119 suffix = "_msan"
120 }
121
122 if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", buildcfg.GOROOT, buildcfg.GOOS, buildcfg.GOARCH, suffix, path)); err == nil {
123 return file, nil
124 }
125 if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.o", buildcfg.GOROOT, buildcfg.GOOS, buildcfg.GOARCH, suffix, path)); err == nil {
126 return file, nil
127 }
128 }
129 return nil, errors.New("file not found")
130 }
131
132
133
134 var myheight int
135
136
137
138 func resolveImportPath(path string) (string, error) {
139
140
141
142
143 if path == "main" {
144 return "", errors.New("cannot import \"main\"")
145 }
146
147 if base.Ctxt.Pkgpath != "" && path == base.Ctxt.Pkgpath {
148 return "", fmt.Errorf("import %q while compiling that package (import cycle)", path)
149 }
150
151 if mapped, ok := base.Flag.Cfg.ImportMap[path]; ok {
152 path = mapped
153 }
154
155 if islocalname(path) {
156 if path[0] == '/' {
157 return "", errors.New("import path cannot be absolute path")
158 }
159
160 prefix := base.Flag.D
161 if prefix == "" {
162
163
164
165
166 prefix = base.Ctxt.Pathname
167 }
168 path = pathpkg.Join(prefix, path)
169
170 if err := checkImportPath(path, true); err != nil {
171 return "", err
172 }
173 }
174
175 return path, nil
176 }
177
178
179 func importfile(decl *syntax.ImportDecl) *types.Pkg {
180 if decl.Path.Kind != syntax.StringLit {
181 base.Errorf("import path must be a string")
182 return nil
183 }
184
185 path, err := strconv.Unquote(decl.Path.Value)
186 if err != nil {
187 base.Errorf("import path must be a string")
188 return nil
189 }
190
191 if err := checkImportPath(path, false); err != nil {
192 base.Errorf("%s", err.Error())
193 return nil
194 }
195
196 path, err = resolveImportPath(path)
197 if err != nil {
198 base.Errorf("%s", err)
199 return nil
200 }
201
202 importpkg := types.NewPkg(path, "")
203 if importpkg.Direct {
204 return importpkg
205 }
206 importpkg.Direct = true
207 typecheck.Target.Imports = append(typecheck.Target.Imports, importpkg)
208
209 if path == "unsafe" {
210 return importpkg
211 }
212
213 f, err := openPackage(path)
214 if err != nil {
215 base.Errorf("could not import %q: %v", path, err)
216 base.ErrorExit()
217 }
218 imp := bio.NewReader(f)
219 defer imp.Close()
220 file := f.Name()
221
222
223 p, err := imp.ReadString('\n')
224 if err != nil {
225 base.Errorf("import %s: reading input: %v", file, err)
226 base.ErrorExit()
227 }
228
229 if p == "!<arch>\n" {
230
231 sz := archive.ReadHeader(imp.Reader, "__.PKGDEF")
232 if sz <= 0 {
233 base.Errorf("import %s: not a package file", file)
234 base.ErrorExit()
235 }
236 p, err = imp.ReadString('\n')
237 if err != nil {
238 base.Errorf("import %s: reading input: %v", file, err)
239 base.ErrorExit()
240 }
241 }
242
243 if !strings.HasPrefix(p, "go object ") {
244 base.Errorf("import %s: not a go object file: %s", file, p)
245 base.ErrorExit()
246 }
247 q := objabi.HeaderString()
248 if p != q {
249 base.Errorf("import %s: object is [%s] expected [%s]", file, p, q)
250 base.ErrorExit()
251 }
252
253
254 for {
255 p, err = imp.ReadString('\n')
256 if err != nil {
257 base.Errorf("import %s: reading input: %v", file, err)
258 base.ErrorExit()
259 }
260 if p == "\n" {
261 break
262 }
263 }
264
265
266
267
268 var c byte
269 for {
270 c, err = imp.ReadByte()
271 if err != nil {
272 break
273 }
274 if c == '$' {
275 c, err = imp.ReadByte()
276 if c == '$' || err != nil {
277 break
278 }
279 }
280 }
281
282
283 if err == nil {
284 c, _ = imp.ReadByte()
285 }
286
287 var fingerprint goobj.FingerprintType
288 switch c {
289 case '\n':
290 base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path)
291 return nil
292
293 case 'B':
294 if base.Debug.Export != 0 {
295 fmt.Printf("importing %s (%s)\n", path, file)
296 }
297 imp.ReadByte()
298
299 c, err = imp.ReadByte()
300 if err != nil {
301 base.Errorf("import %s: reading input: %v", file, err)
302 base.ErrorExit()
303 }
304
305
306
307 if c != 'i' {
308 base.Errorf("import %s: unexpected package format byte: %v", file, c)
309 base.ErrorExit()
310 }
311 fingerprint = typecheck.ReadImports(importpkg, imp)
312
313 default:
314 base.Errorf("no import in %q", path)
315 base.ErrorExit()
316 }
317
318
319 if base.Flag.Cfg.PackageFile != nil {
320
321 base.Ctxt.AddImport(path, fingerprint)
322 } else {
323
324 base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint)
325 }
326
327 if importpkg.Height >= myheight {
328 myheight = importpkg.Height + 1
329 }
330
331 return importpkg
332 }
333
334
335
336
337
338
339 var reservedimports = []string{
340 "go",
341 "type",
342 }
343
344 func checkImportPath(path string, allowSpace bool) error {
345 if path == "" {
346 return errors.New("import path is empty")
347 }
348
349 if strings.Contains(path, "\x00") {
350 return errors.New("import path contains NUL")
351 }
352
353 for _, ri := range reservedimports {
354 if path == ri {
355 return fmt.Errorf("import path %q is reserved and cannot be used", path)
356 }
357 }
358
359 for _, r := range path {
360 switch {
361 case r == utf8.RuneError:
362 return fmt.Errorf("import path contains invalid UTF-8 sequence: %q", path)
363 case r < 0x20 || r == 0x7f:
364 return fmt.Errorf("import path contains control character: %q", path)
365 case r == '\\':
366 return fmt.Errorf("import path contains backslash; use slash: %q", path)
367 case !allowSpace && unicode.IsSpace(r):
368 return fmt.Errorf("import path contains space character: %q", path)
369 case strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r):
370 return fmt.Errorf("import path contains invalid character '%c': %q", r, path)
371 }
372 }
373
374 return nil
375 }
376
377 func pkgnotused(lineno src.XPos, path string, name string) {
378
379
380
381
382
383
384 elem := path
385 if i := strings.LastIndex(elem, "/"); i >= 0 {
386 elem = elem[i+1:]
387 }
388 if name == "" || elem == name {
389 base.ErrorfAt(lineno, "imported and not used: %q", path)
390 } else {
391 base.ErrorfAt(lineno, "imported and not used: %q as %s", path, name)
392 }
393 }
394
395 func mkpackage(pkgname string) {
396 if types.LocalPkg.Name == "" {
397 if pkgname == "_" {
398 base.Errorf("invalid package name _")
399 }
400 types.LocalPkg.Name = pkgname
401 } else {
402 if pkgname != types.LocalPkg.Name {
403 base.Errorf("package %s; expected %s", pkgname, types.LocalPkg.Name)
404 }
405 }
406 }
407
408 func clearImports() {
409 type importedPkg struct {
410 pos src.XPos
411 path string
412 name string
413 }
414 var unused []importedPkg
415
416 for _, s := range types.LocalPkg.Syms {
417 n := ir.AsNode(s.Def)
418 if n == nil {
419 continue
420 }
421 if n.Op() == ir.OPACK {
422
423
424
425
426
427 p := n.(*ir.PkgName)
428 if !p.Used && base.SyntaxErrors() == 0 {
429 unused = append(unused, importedPkg{p.Pos(), p.Pkg.Path, s.Name})
430 }
431 s.Def = nil
432 continue
433 }
434 if types.IsDotAlias(s) {
435
436
437
438 s.Def = nil
439 continue
440 }
441 }
442
443 sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
444 for _, pkg := range unused {
445 pkgnotused(pkg.pos, pkg.path, pkg.name)
446 }
447 }
448
449
450 func CheckDotImports() {
451 for _, pack := range dotImports {
452 if !pack.Used {
453 base.ErrorfAt(pack.Pos(), "imported and not used: %q", pack.Pkg.Path)
454 }
455 }
456
457
458 dotImports = nil
459 typecheck.DotImportRefs = nil
460 }
461
462
463 var dotImports []*ir.PkgName
464
465
466
467 func importDot(pack *ir.PkgName) {
468 if typecheck.DotImportRefs == nil {
469 typecheck.DotImportRefs = make(map[*ir.Ident]*ir.PkgName)
470 }
471
472 opkg := pack.Pkg
473 for _, s := range opkg.Syms {
474 if s.Def == nil {
475 if _, ok := typecheck.DeclImporter[s]; !ok {
476 continue
477 }
478 }
479 if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) {
480 continue
481 }
482 s1 := typecheck.Lookup(s.Name)
483 if s1.Def != nil {
484 pkgerror := fmt.Sprintf("during import %q", opkg.Path)
485 typecheck.Redeclared(base.Pos, s1, pkgerror)
486 continue
487 }
488
489 id := ir.NewIdent(src.NoXPos, s)
490 typecheck.DotImportRefs[id] = pack
491 s1.Def = id
492 s1.Block = 1
493 }
494
495 dotImports = append(dotImports, pack)
496 }
497
498
499
500 func importName(sym *types.Sym) ir.Node {
501 n := oldname(sym)
502 if !types.IsExported(sym.Name) && sym.Pkg != types.LocalPkg {
503 n.SetDiag(true)
504 base.Errorf("cannot refer to unexported name %s.%s", sym.Pkg.Name, sym.Name)
505 }
506 return n
507 }
508
View as plain text