]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/build/deps_test.go
maps,runtime: improve maps.Keys
[gostls13.git] / src / go / build / deps_test.go
1 // Copyright 2022 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 // This file exercises the import parser but also checks that
6 // some low-level packages do not have new dependencies added.
7
8 package build
9
10 import (
11         "bytes"
12         "fmt"
13         "go/token"
14         "internal/dag"
15         "internal/testenv"
16         "io/fs"
17         "os"
18         "path/filepath"
19         "runtime"
20         "sort"
21         "strings"
22         "testing"
23 )
24
25 // depsRules defines the expected dependencies between packages in
26 // the Go source tree. It is a statement of policy.
27 //
28 // DO NOT CHANGE THIS DATA TO FIX BUILDS.
29 // Existing packages should not have their constraints relaxed
30 // without prior discussion.
31 // Negative assertions should almost never be removed.
32 //
33 // "a < b" means package b can import package a.
34 //
35 // See `go doc internal/dag' for the full syntax.
36 //
37 // All-caps names are pseudo-names for specific points
38 // in the dependency lattice.
39 var depsRules = `
40         # No dependencies allowed for any of these packages.
41         NONE
42         < constraints, container/list, container/ring,
43           internal/cfg, internal/coverage, internal/coverage/rtcov,
44           internal/coverage/uleb128, internal/coverage/calloc,
45           internal/cpu, internal/goarch, internal/godebugs,
46           internal/goexperiment, internal/goos,
47           internal/goversion, internal/nettrace, internal/platform,
48           log/internal,
49           unicode/utf8, unicode/utf16, unicode,
50           unsafe;
51
52         # slices depends on unsafe for overlapping check.
53         unsafe
54         < slices;
55
56         # These packages depend only on internal/goarch and unsafe.
57         internal/goarch, unsafe
58         < internal/abi;
59
60         unsafe < maps;
61
62         # RUNTIME is the core runtime group of packages, all of them very light-weight.
63         internal/abi, internal/cpu, internal/goarch,
64         internal/coverage/rtcov, internal/godebugs, internal/goexperiment,
65         internal/goos, unsafe
66         < internal/bytealg
67         < internal/itoa
68         < internal/unsafeheader
69         < runtime/internal/sys
70         < runtime/internal/syscall
71         < runtime/internal/atomic
72         < runtime/internal/math
73         < runtime
74         < sync/atomic
75         < internal/race
76         < sync
77         < internal/bisect
78         < internal/godebug
79         < internal/reflectlite
80         < errors
81         < internal/oserror, math/bits
82         < RUNTIME;
83
84         RUNTIME
85         < sort
86         < container/heap;
87
88         RUNTIME
89         < io;
90
91         RUNTIME
92         < arena;
93
94         syscall !< io;
95         reflect !< sort;
96
97         RUNTIME, unicode/utf8
98         < path;
99
100         unicode !< path;
101
102         # SYSCALL is RUNTIME plus the packages necessary for basic system calls.
103         RUNTIME, unicode/utf8, unicode/utf16
104         < internal/syscall/windows/sysdll, syscall/js
105         < syscall
106         < internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
107         < internal/syscall/execenv
108         < SYSCALL;
109
110         # TIME is SYSCALL plus the core packages about time, including context.
111         SYSCALL
112         < time/tzdata
113         < time
114         < context
115         < TIME;
116
117         TIME, io, path, sort
118         < io/fs;
119
120         # MATH is RUNTIME plus the basic math packages.
121         RUNTIME
122         < math
123         < MATH;
124
125         unicode !< math;
126
127         MATH
128         < math/cmplx;
129
130         MATH
131         < math/rand;
132
133         MATH
134         < runtime/metrics;
135
136         MATH, unicode/utf8
137         < strconv;
138
139         unicode !< strconv;
140
141         # STR is basic string and buffer manipulation.
142         RUNTIME, io, unicode/utf8, unicode/utf16, unicode
143         < bytes, strings
144         < bufio;
145
146         bufio, path, strconv
147         < STR;
148
149         # OS is basic OS access, including helpers (path/filepath, os/exec, etc).
150         # OS includes string routines, but those must be layered above package os.
151         # OS does not include reflection.
152         io/fs
153         < internal/testlog
154         < internal/poll
155         < internal/safefilepath
156         < os
157         < os/signal;
158
159         io/fs
160         < embed;
161
162         unicode, fmt !< net, os, os/signal;
163
164         os/signal, STR
165         < path/filepath
166         < io/ioutil;
167
168         path/filepath, internal/godebug < os/exec;
169
170         io/ioutil, os/exec, os/signal
171         < OS;
172
173         reflect !< OS;
174
175         OS
176         < golang.org/x/sys/cpu;
177
178         # FMT is OS (which includes string routines) plus reflect and fmt.
179         # It does not include package log, which should be avoided in core packages.
180         arena, strconv, unicode
181         < reflect;
182
183         os, reflect
184         < internal/fmtsort
185         < fmt;
186
187         OS, fmt
188         < FMT;
189
190         log !< FMT;
191
192         # Misc packages needing only FMT.
193         FMT
194         < html,
195           internal/dag,
196           internal/goroot,
197           internal/types/errors,
198           mime/quotedprintable,
199           net/internal/socktest,
200           net/url,
201           runtime/trace,
202           text/scanner,
203           text/tabwriter;
204
205         io, reflect
206         < internal/saferio;
207
208         # encodings
209         # core ones do not use fmt.
210         io, strconv
211         < encoding;
212
213         encoding, reflect
214         < encoding/binary
215         < encoding/base32, encoding/base64;
216
217         FMT, encoding < flag;
218
219         fmt !< encoding/base32, encoding/base64;
220
221         FMT, encoding/base32, encoding/base64, internal/saferio
222         < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
223           encoding/json, encoding/pem, encoding/xml, mime;
224
225         # hashes
226         io
227         < hash
228         < hash/adler32, hash/crc32, hash/crc64, hash/fnv;
229
230         # math/big
231         FMT, encoding/binary, math/rand
232         < math/big;
233
234         # compression
235         FMT, encoding/binary, hash/adler32, hash/crc32
236         < compress/bzip2, compress/flate, compress/lzw, internal/zstd
237         < archive/zip, compress/gzip, compress/zlib;
238
239         # templates
240         FMT
241         < text/template/parse;
242
243         net/url, text/template/parse
244         < text/template
245         < internal/lazytemplate;
246
247         encoding/json, html, text/template
248         < html/template;
249
250         # regexp
251         FMT
252         < regexp/syntax
253         < regexp
254         < internal/lazyregexp;
255
256         # suffix array
257         encoding/binary, regexp
258         < index/suffixarray;
259
260         # executable parsing
261         FMT, encoding/binary, compress/zlib, internal/saferio, internal/zstd
262         < runtime/debug
263         < debug/dwarf
264         < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
265         < debug/buildinfo
266         < DEBUG;
267
268         # go parser and friends.
269         FMT
270         < go/token
271         < go/scanner
272         < go/ast
273         < go/internal/typeparams;
274
275         FMT
276         < go/build/constraint, go/doc/comment;
277
278         go/internal/typeparams, go/build/constraint
279         < go/parser;
280
281         go/doc/comment, go/parser, text/tabwriter
282         < go/printer
283         < go/format;
284
285         math/big, go/token
286         < go/constant;
287
288         container/heap, go/constant, go/parser, internal/types/errors
289         < go/types;
290
291         # The vast majority of standard library packages should not be resorting to regexp.
292         # go/types is a good chokepoint. It shouldn't use regexp, nor should anything
293         # that is low-enough level to be used by go/types.
294         regexp !< go/types;
295
296         go/doc/comment, go/parser, internal/lazyregexp, text/template
297         < go/doc;
298
299         FMT, internal/goexperiment
300         < internal/buildcfg;
301
302         go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion, internal/platform
303         < go/build;
304
305         # databases
306         FMT
307         < database/sql/internal
308         < database/sql/driver
309         < database/sql;
310
311         # images
312         FMT, compress/lzw, compress/zlib
313         < image/color
314         < image, image/color/palette
315         < image/internal/imageutil
316         < image/draw
317         < image/gif, image/jpeg, image/png;
318
319         # cgo, delayed as long as possible.
320         # If you add a dependency on CGO, you must add the package
321         # to cgoPackages in cmd/dist/test.go as well.
322         RUNTIME
323         < C
324         < runtime/cgo
325         < CGO
326         < runtime/msan, runtime/asan;
327
328         # runtime/race
329         NONE < runtime/race/internal/amd64v1;
330         NONE < runtime/race/internal/amd64v3;
331         CGO, runtime/race/internal/amd64v1, runtime/race/internal/amd64v3 < runtime/race;
332
333         # Bulk of the standard library must not use cgo.
334         # The prohibition stops at net and os/user.
335         C !< fmt, go/types, CRYPTO-MATH, log/slog;
336
337         CGO, OS
338         < plugin;
339
340         CGO, FMT
341         < os/user
342         < archive/tar;
343
344         sync
345         < internal/singleflight;
346
347         os
348         < golang.org/x/net/dns/dnsmessage,
349           golang.org/x/net/lif,
350           golang.org/x/net/route;
351
352         os, runtime, strconv, sync, unsafe,
353         internal/godebug
354         < internal/intern;
355
356         internal/bytealg, internal/intern, internal/itoa, math/bits, sort, strconv
357         < net/netip;
358
359         # net is unavoidable when doing any networking,
360         # so large dependencies must be kept out.
361         # This is a long-looking list but most of these
362         # are small with few dependencies.
363         CGO,
364         golang.org/x/net/dns/dnsmessage,
365         golang.org/x/net/lif,
366         golang.org/x/net/route,
367         internal/godebug,
368         internal/nettrace,
369         internal/poll,
370         internal/singleflight,
371         internal/race,
372         net/netip,
373         os
374         < net;
375
376         fmt, unicode !< net;
377         math/rand !< net; # net uses runtime instead
378
379         # NET is net plus net-helper packages.
380         FMT, net
381         < net/textproto;
382
383         mime, net/textproto, net/url
384         < NET;
385
386         # logging - most packages should not import; http and up is allowed
387         FMT, log/internal
388         < log;
389
390         log, log/slog !< crypto/tls, database/sql, go/importer, testing;
391
392         FMT, log, net
393         < log/syslog;
394
395         RUNTIME
396         < log/slog/internal, log/slog/internal/buffer;
397
398         FMT,
399         encoding, encoding/json,
400         log, log/internal,
401         log/slog/internal, log/slog/internal/buffer,
402         slices
403         < log/slog
404         < log/slog/internal/slogtest, log/slog/internal/benchmarks;
405
406         NET, log
407         < net/mail;
408
409         NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
410         sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fipstls;
411         crypto/internal/boring/sig, crypto/internal/boring/fipstls < crypto/tls/fipsonly;
412
413         # CRYPTO is core crypto algorithms - no cgo, fmt, net.
414         # Unfortunately, stuck with reflect via encoding/binary.
415         crypto/internal/boring/sig,
416         crypto/internal/boring/syso,
417         encoding/binary,
418         golang.org/x/sys/cpu,
419         hash, embed
420         < crypto
421         < crypto/subtle
422         < crypto/internal/alias
423         < crypto/cipher;
424
425         crypto/cipher,
426         crypto/internal/boring/bcache
427         < crypto/internal/boring
428         < crypto/boring;
429
430         crypto/internal/alias
431         < crypto/internal/randutil
432         < crypto/internal/nistec/fiat
433         < crypto/internal/nistec
434         < crypto/internal/edwards25519/field
435         < crypto/internal/edwards25519;
436
437         crypto/boring
438         < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
439           crypto/sha1, crypto/sha256, crypto/sha512;
440
441         crypto/boring, crypto/internal/edwards25519/field
442         < crypto/ecdh;
443
444         crypto/aes,
445         crypto/des,
446         crypto/ecdh,
447         crypto/hmac,
448         crypto/internal/edwards25519,
449         crypto/md5,
450         crypto/rc4,
451         crypto/sha1,
452         crypto/sha256,
453         crypto/sha512
454         < CRYPTO;
455
456         CGO, fmt, net !< CRYPTO;
457
458         # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
459         CRYPTO, FMT, math/big
460         < crypto/internal/boring/bbig
461         < crypto/rand
462         < crypto/ed25519
463         < encoding/asn1
464         < golang.org/x/crypto/cryptobyte/asn1
465         < golang.org/x/crypto/cryptobyte
466         < crypto/internal/bigmod
467         < crypto/dsa, crypto/elliptic, crypto/rsa
468         < crypto/ecdsa
469         < CRYPTO-MATH;
470
471         CGO, net !< CRYPTO-MATH;
472
473         # TLS, Prince of Dependencies.
474         CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
475         < golang.org/x/crypto/internal/alias
476         < golang.org/x/crypto/internal/subtle
477         < golang.org/x/crypto/chacha20
478         < golang.org/x/crypto/internal/poly1305
479         < golang.org/x/crypto/chacha20poly1305
480         < golang.org/x/crypto/hkdf
481         < crypto/x509/internal/macos
482         < crypto/x509/pkix;
483
484         crypto/internal/boring/fipstls, crypto/x509/pkix
485         < crypto/x509
486         < crypto/tls;
487
488         # crypto-aware packages
489
490         DEBUG, go/build, go/types, text/scanner, crypto/md5
491         < internal/pkgbits
492         < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
493         < go/importer;
494
495         NET, crypto/rand, mime/quotedprintable
496         < mime/multipart;
497
498         crypto/tls
499         < net/smtp;
500
501         crypto/rand
502         < hash/maphash; # for purego implementation
503
504         # HTTP, King of Dependencies.
505
506         FMT
507         < golang.org/x/net/http2/hpack
508         < net/http/internal, net/http/internal/ascii, net/http/internal/testcert;
509
510         FMT, NET, container/list, encoding/binary, log
511         < golang.org/x/text/transform
512         < golang.org/x/text/unicode/norm
513         < golang.org/x/text/unicode/bidi
514         < golang.org/x/text/secure/bidirule
515         < golang.org/x/net/idna
516         < golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
517
518         NET, crypto/tls
519         < net/http/httptrace;
520
521         compress/gzip,
522         golang.org/x/net/http/httpguts,
523         golang.org/x/net/http/httpproxy,
524         golang.org/x/net/http2/hpack,
525         net/http/internal,
526         net/http/internal/ascii,
527         net/http/internal/testcert,
528         net/http/httptrace,
529         mime/multipart,
530         log
531         < net/http;
532
533         # HTTP-aware packages
534
535         encoding/json, net/http
536         < expvar;
537
538         net/http, net/http/internal/ascii
539         < net/http/cookiejar, net/http/httputil;
540
541         net/http, flag
542         < net/http/httptest;
543
544         net/http, regexp
545         < net/http/cgi
546         < net/http/fcgi;
547
548         # Profiling
549         FMT, compress/gzip, encoding/binary, text/tabwriter
550         < runtime/pprof;
551
552         OS, compress/gzip, internal/lazyregexp
553         < internal/profile;
554
555         html, internal/profile, net/http, runtime/pprof, runtime/trace
556         < net/http/pprof;
557
558         # RPC
559         encoding/gob, encoding/json, go/token, html/template, net/http
560         < net/rpc
561         < net/rpc/jsonrpc;
562
563         # System Information
564         internal/cpu, sync
565         < internal/sysinfo;
566
567         # Test-only
568         log
569         < testing/iotest
570         < testing/fstest;
571
572         log/slog
573         < testing/slogtest;
574
575         FMT, flag, math/rand
576         < testing/quick;
577
578         FMT, DEBUG, flag, runtime/trace, internal/sysinfo, math/rand
579         < testing;
580
581         FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token,
582         internal/godebug, math/rand, encoding/hex, crypto/sha256
583         < internal/fuzz;
584
585         internal/fuzz, internal/testlog, runtime/pprof, regexp
586         < testing/internal/testdeps;
587
588         OS, flag, testing, internal/cfg, internal/platform, internal/goroot
589         < internal/testenv;
590
591         OS, encoding/base64
592         < internal/obscuretestdata;
593
594         CGO, OS, fmt
595         < internal/testpty;
596
597         NET, testing, math/rand
598         < golang.org/x/net/nettest;
599
600         syscall
601         < os/exec/internal/fdtest;
602
603         FMT, container/heap, math/rand
604         < internal/trace;
605
606         FMT
607         < internal/diff, internal/txtar;
608
609         FMT, crypto/md5, encoding/binary, regexp, sort, text/tabwriter, unsafe,
610         internal/coverage, internal/coverage/uleb128
611         < internal/coverage/cmerge,
612           internal/coverage/pods,
613           internal/coverage/slicereader,
614           internal/coverage/slicewriter;
615
616         internal/coverage/slicereader, internal/coverage/slicewriter
617         < internal/coverage/stringtab
618         < internal/coverage/decodecounter, internal/coverage/decodemeta,
619           internal/coverage/encodecounter, internal/coverage/encodemeta;
620
621         internal/coverage/cmerge
622         < internal/coverage/cformat;
623
624         runtime/debug,
625         internal/coverage/calloc,
626         internal/coverage/cformat,
627         internal/coverage/decodecounter, internal/coverage/decodemeta,
628         internal/coverage/encodecounter, internal/coverage/encodemeta,
629         internal/coverage/pods
630         < runtime/coverage;
631 `
632
633 // listStdPkgs returns the same list of packages as "go list std".
634 func listStdPkgs(goroot string) ([]string, error) {
635         // Based on cmd/go's matchPackages function.
636         var pkgs []string
637
638         src := filepath.Join(goroot, "src") + string(filepath.Separator)
639         walkFn := func(path string, d fs.DirEntry, err error) error {
640                 if err != nil || !d.IsDir() || path == src {
641                         return nil
642                 }
643
644                 base := filepath.Base(path)
645                 if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
646                         return filepath.SkipDir
647                 }
648
649                 name := filepath.ToSlash(path[len(src):])
650                 if name == "builtin" || name == "cmd" {
651                         return filepath.SkipDir
652                 }
653
654                 pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
655                 return nil
656         }
657         if err := filepath.WalkDir(src, walkFn); err != nil {
658                 return nil, err
659         }
660         return pkgs, nil
661 }
662
663 func TestDependencies(t *testing.T) {
664         if !testenv.HasSrc() {
665                 // Tests run in a limited file system and we do not
666                 // provide access to every source file.
667                 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
668         }
669
670         ctxt := Default
671         all, err := listStdPkgs(ctxt.GOROOT)
672         if err != nil {
673                 t.Fatal(err)
674         }
675         sort.Strings(all)
676
677         sawImport := map[string]map[string]bool{} // from package => to package => true
678         policy := depsPolicy(t)
679
680         for _, pkg := range all {
681                 imports, err := findImports(pkg)
682                 if err != nil {
683                         t.Error(err)
684                         continue
685                 }
686                 if sawImport[pkg] == nil {
687                         sawImport[pkg] = map[string]bool{}
688                 }
689                 var bad []string
690                 for _, imp := range imports {
691                         sawImport[pkg][imp] = true
692                         if !policy.HasEdge(pkg, imp) {
693                                 bad = append(bad, imp)
694                         }
695                 }
696                 if bad != nil {
697                         t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
698                 }
699         }
700 }
701
702 var buildIgnore = []byte("\n//go:build ignore")
703
704 func findImports(pkg string) ([]string, error) {
705         vpkg := pkg
706         if strings.HasPrefix(pkg, "golang.org") {
707                 vpkg = "vendor/" + pkg
708         }
709         dir := filepath.Join(Default.GOROOT, "src", vpkg)
710         files, err := os.ReadDir(dir)
711         if err != nil {
712                 return nil, err
713         }
714         var imports []string
715         var haveImport = map[string]bool{}
716         if pkg == "crypto/internal/boring" {
717                 haveImport["C"] = true // kludge: prevent C from appearing in crypto/internal/boring imports
718         }
719         fset := token.NewFileSet()
720         for _, file := range files {
721                 name := file.Name()
722                 if name == "slice_go14.go" || name == "slice_go18.go" {
723                         // These files are for compiler bootstrap with older versions of Go and not built in the standard build.
724                         continue
725                 }
726                 if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
727                         continue
728                 }
729                 info := fileInfo{
730                         name: filepath.Join(dir, name),
731                         fset: fset,
732                 }
733                 f, err := os.Open(info.name)
734                 if err != nil {
735                         return nil, err
736                 }
737                 err = readGoInfo(f, &info)
738                 f.Close()
739                 if err != nil {
740                         return nil, fmt.Errorf("reading %v: %v", name, err)
741                 }
742                 if info.parsed.Name.Name == "main" {
743                         continue
744                 }
745                 if bytes.Contains(info.header, buildIgnore) {
746                         continue
747                 }
748                 for _, imp := range info.imports {
749                         path := imp.path
750                         if !haveImport[path] {
751                                 haveImport[path] = true
752                                 imports = append(imports, path)
753                         }
754                 }
755         }
756         sort.Strings(imports)
757         return imports, nil
758 }
759
760 // depsPolicy returns a map m such that m[p][d] == true when p can import d.
761 func depsPolicy(t *testing.T) *dag.Graph {
762         g, err := dag.Parse(depsRules)
763         if err != nil {
764                 t.Fatal(err)
765         }
766         return g
767 }
768
769 // TestStdlibLowercase tests that all standard library package names are
770 // lowercase. See Issue 40065.
771 func TestStdlibLowercase(t *testing.T) {
772         if !testenv.HasSrc() {
773                 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
774         }
775
776         ctxt := Default
777         all, err := listStdPkgs(ctxt.GOROOT)
778         if err != nil {
779                 t.Fatal(err)
780         }
781
782         for _, pkgname := range all {
783                 if strings.ToLower(pkgname) != pkgname {
784                         t.Errorf("package %q should not use upper-case path", pkgname)
785                 }
786         }
787 }
788
789 // TestFindImports tests that findImports works.  See #43249.
790 func TestFindImports(t *testing.T) {
791         imports, err := findImports("go/build")
792         if err != nil {
793                 t.Fatal(err)
794         }
795         t.Logf("go/build imports %q", imports)
796         want := []string{"bytes", "os", "path/filepath", "strings"}
797 wantLoop:
798         for _, w := range want {
799                 for _, imp := range imports {
800                         if imp == w {
801                                 continue wantLoop
802                         }
803                 }
804                 t.Errorf("expected to find %q in import list", w)
805         }
806 }