Source file
src/go/doc/reader.go
1
2
3
4
5 package doc
6
7 import (
8 "fmt"
9 "go/ast"
10 "go/token"
11 "internal/lazyregexp"
12 "sort"
13 "strconv"
14 "strings"
15 )
16
17
18
19
20
21
22
23
24
25 type methodSet map[string]*Func
26
27
28
29
30 func recvString(recv ast.Expr) string {
31 switch t := recv.(type) {
32 case *ast.Ident:
33 return t.Name
34 case *ast.StarExpr:
35 return "*" + recvString(t.X)
36 case *ast.IndexExpr:
37
38 return fmt.Sprintf("%s[%s]", recvString(t.X), recvParam(t.Index))
39 case *ast.IndexListExpr:
40
41 if len(t.Indices) > 0 {
42 var b strings.Builder
43 b.WriteString(recvString(t.X))
44 b.WriteByte('[')
45 b.WriteString(recvParam(t.Indices[0]))
46 for _, e := range t.Indices[1:] {
47 b.WriteString(", ")
48 b.WriteString(recvParam(e))
49 }
50 b.WriteByte(']')
51 return b.String()
52 }
53 }
54 return "BADRECV"
55 }
56
57 func recvParam(p ast.Expr) string {
58 if id, ok := p.(*ast.Ident); ok {
59 return id.Name
60 }
61 return "BADPARAM"
62 }
63
64
65
66
67
68
69 func (mset methodSet) set(f *ast.FuncDecl, preserveAST bool) {
70 name := f.Name.Name
71 if g := mset[name]; g != nil && g.Doc != "" {
72
73
74
75
76
77 return
78 }
79
80 recv := ""
81 if f.Recv != nil {
82 var typ ast.Expr
83
84 if list := f.Recv.List; len(list) == 1 {
85 typ = list[0].Type
86 }
87 recv = recvString(typ)
88 }
89 mset[name] = &Func{
90 Doc: f.Doc.Text(),
91 Name: name,
92 Decl: f,
93 Recv: recv,
94 Orig: recv,
95 }
96 if !preserveAST {
97 f.Doc = nil
98 }
99 }
100
101
102
103
104
105 func (mset methodSet) add(m *Func) {
106 old := mset[m.Name]
107 if old == nil || m.Level < old.Level {
108 mset[m.Name] = m
109 return
110 }
111 if m.Level == old.Level {
112
113 mset[m.Name] = &Func{
114 Name: m.Name,
115 Level: m.Level,
116 }
117 }
118 }
119
120
121
122
123
124
125
126 func baseTypeName(x ast.Expr) (name string, imported bool) {
127 switch t := x.(type) {
128 case *ast.Ident:
129 return t.Name, false
130 case *ast.IndexExpr:
131 return baseTypeName(t.X)
132 case *ast.IndexListExpr:
133 return baseTypeName(t.X)
134 case *ast.SelectorExpr:
135 if _, ok := t.X.(*ast.Ident); ok {
136
137
138 return t.Sel.Name, true
139 }
140 case *ast.ParenExpr:
141 return baseTypeName(t.X)
142 case *ast.StarExpr:
143 return baseTypeName(t.X)
144 }
145 return "", false
146 }
147
148
149 type embeddedSet map[*namedType]bool
150
151
152
153
154
155 type namedType struct {
156 doc string
157 name string
158 decl *ast.GenDecl
159
160 isEmbedded bool
161 isStruct bool
162 embedded embeddedSet
163
164
165 values []*Value
166 funcs methodSet
167 methods methodSet
168 }
169
170
171
172
173
174
175
176
177
178
179
180 type reader struct {
181 mode Mode
182
183
184 doc string
185 filenames []string
186 notes map[string][]*Note
187
188
189 imports map[string]int
190 hasDotImp bool
191 values []*Value
192 order int
193 types map[string]*namedType
194 funcs methodSet
195
196
197 shadowedPredecl map[string]bool
198 fixmap map[string][]*ast.InterfaceType
199 }
200
201 func (r *reader) isVisible(name string) bool {
202 return r.mode&AllDecls != 0 || token.IsExported(name)
203 }
204
205
206
207
208
209
210 func (r *reader) lookupType(name string) *namedType {
211 if name == "" || name == "_" {
212 return nil
213 }
214 if typ, found := r.types[name]; found {
215 return typ
216 }
217
218 typ := &namedType{
219 name: name,
220 embedded: make(embeddedSet),
221 funcs: make(methodSet),
222 methods: make(methodSet),
223 }
224 r.types[name] = typ
225 return typ
226 }
227
228
229
230
231
232
233 func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) {
234 fname, imp := baseTypeName(fieldType)
235 if parent == nil || imp {
236 return
237 }
238 if ftype := r.lookupType(fname); ftype != nil {
239 ftype.isEmbedded = true
240 _, ptr := fieldType.(*ast.StarExpr)
241 parent.embedded[ftype] = ptr
242 }
243 return
244 }
245
246 func (r *reader) readDoc(comment *ast.CommentGroup) {
247
248
249 text := comment.Text()
250 if r.doc == "" {
251 r.doc = text
252 return
253 }
254 r.doc += "\n" + text
255 }
256
257 func (r *reader) remember(predecl string, typ *ast.InterfaceType) {
258 if r.fixmap == nil {
259 r.fixmap = make(map[string][]*ast.InterfaceType)
260 }
261 r.fixmap[predecl] = append(r.fixmap[predecl], typ)
262 }
263
264 func specNames(specs []ast.Spec) []string {
265 names := make([]string, 0, len(specs))
266 for _, s := range specs {
267
268 for _, ident := range s.(*ast.ValueSpec).Names {
269 names = append(names, ident.Name)
270 }
271 }
272 return names
273 }
274
275
276
277 func (r *reader) readValue(decl *ast.GenDecl) {
278
279
280
281
282 domName := ""
283 domFreq := 0
284 prev := ""
285 n := 0
286 for _, spec := range decl.Specs {
287 s, ok := spec.(*ast.ValueSpec)
288 if !ok {
289 continue
290 }
291 name := ""
292 switch {
293 case s.Type != nil:
294
295 if n, imp := baseTypeName(s.Type); !imp {
296 name = n
297 }
298 case decl.Tok == token.CONST && len(s.Values) == 0:
299
300
301 name = prev
302 }
303 if name != "" {
304
305 if domName != "" && domName != name {
306
307
308 domName = ""
309 break
310 }
311 domName = name
312 domFreq++
313 }
314 prev = name
315 n++
316 }
317
318
319 if n == 0 {
320 return
321 }
322
323
324 values := &r.values
325 const threshold = 0.75
326 if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) {
327
328 if typ := r.lookupType(domName); typ != nil {
329 values = &typ.values
330 }
331 }
332
333 *values = append(*values, &Value{
334 Doc: decl.Doc.Text(),
335 Names: specNames(decl.Specs),
336 Decl: decl,
337 order: r.order,
338 })
339 if r.mode&PreserveAST == 0 {
340 decl.Doc = nil
341 }
342
343
344
345
346 r.order++
347 }
348
349
350
351 func fields(typ ast.Expr) (list []*ast.Field, isStruct bool) {
352 var fields *ast.FieldList
353 switch t := typ.(type) {
354 case *ast.StructType:
355 fields = t.Fields
356 isStruct = true
357 case *ast.InterfaceType:
358 fields = t.Methods
359 }
360 if fields != nil {
361 list = fields.List
362 }
363 return
364 }
365
366
367
368 func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
369 typ := r.lookupType(spec.Name.Name)
370 if typ == nil {
371 return
372 }
373
374
375
376 typ.decl = decl
377
378
379 doc := spec.Doc
380 if doc == nil {
381
382 doc = decl.Doc
383 }
384 if r.mode&PreserveAST == 0 {
385 spec.Doc = nil
386 decl.Doc = nil
387 }
388 typ.doc = doc.Text()
389
390
391
392
393 var list []*ast.Field
394 list, typ.isStruct = fields(spec.Type)
395 for _, field := range list {
396 if len(field.Names) == 0 {
397 r.recordAnonymousField(typ, field.Type)
398 }
399 }
400 }
401
402
403
404 func (r *reader) isPredeclared(n string) bool {
405 return predeclaredTypes[n] && r.types[n] == nil
406 }
407
408
409
410 func (r *reader) readFunc(fun *ast.FuncDecl) {
411
412 if r.mode&PreserveAST == 0 {
413 fun.Body = nil
414 }
415
416
417 if fun.Recv != nil {
418
419 if len(fun.Recv.List) == 0 {
420
421
422 return
423 }
424 recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
425 if imp {
426
427
428 return
429 }
430 if typ := r.lookupType(recvTypeName); typ != nil {
431 typ.methods.set(fun, r.mode&PreserveAST != 0)
432 }
433
434
435
436
437
438 return
439 }
440
441
442
443 if fun.Type.Results.NumFields() >= 1 {
444 var typ *namedType
445 numResultTypes := 0
446 for _, res := range fun.Type.Results.List {
447 factoryType := res.Type
448 if t, ok := factoryType.(*ast.ArrayType); ok {
449
450
451 factoryType = t.Elt
452 }
453 if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) && !r.isPredeclared(n) {
454 if lookupTypeParam(n, fun.Type.TypeParams) != nil {
455
456
457 continue
458 }
459 if t := r.lookupType(n); t != nil {
460 typ = t
461 numResultTypes++
462 if numResultTypes > 1 {
463 break
464 }
465 }
466 }
467 }
468
469
470 if numResultTypes == 1 {
471 typ.funcs.set(fun, r.mode&PreserveAST != 0)
472 return
473 }
474 }
475
476
477 r.funcs.set(fun, r.mode&PreserveAST != 0)
478 }
479
480
481
482 func lookupTypeParam(name string, tparams *ast.FieldList) *ast.Ident {
483 if tparams == nil {
484 return nil
485 }
486 for _, field := range tparams.List {
487 for _, id := range field.Names {
488 if id.Name == name {
489 return id
490 }
491 }
492 }
493 return nil
494 }
495
496 var (
497 noteMarker = `([A-Z][A-Z]+)\(([^)]+)\):?`
498 noteMarkerRx = lazyregexp.New(`^[ \t]*` + noteMarker)
499 noteCommentRx = lazyregexp.New(`^/[/*][ \t]*` + noteMarker)
500 )
501
502
503
504 func (r *reader) readNote(list []*ast.Comment) {
505 text := (&ast.CommentGroup{List: list}).Text()
506 if m := noteMarkerRx.FindStringSubmatchIndex(text); m != nil {
507
508
509
510
511 body := clean(text[m[1]:], keepNL)
512 if body != "" {
513 marker := text[m[2]:m[3]]
514 r.notes[marker] = append(r.notes[marker], &Note{
515 Pos: list[0].Pos(),
516 End: list[len(list)-1].End(),
517 UID: text[m[4]:m[5]],
518 Body: body,
519 })
520 }
521 }
522 }
523
524
525
526
527
528
529
530 func (r *reader) readNotes(comments []*ast.CommentGroup) {
531 for _, group := range comments {
532 i := -1
533 list := group.List
534 for j, c := range list {
535 if noteCommentRx.MatchString(c.Text) {
536 if i >= 0 {
537 r.readNote(list[i:j])
538 }
539 i = j
540 }
541 }
542 if i >= 0 {
543 r.readNote(list[i:])
544 }
545 }
546 }
547
548
549
550 func (r *reader) readFile(src *ast.File) {
551
552 if src.Doc != nil {
553 r.readDoc(src.Doc)
554 if r.mode&PreserveAST == 0 {
555 src.Doc = nil
556 }
557 }
558
559
560 for _, decl := range src.Decls {
561 switch d := decl.(type) {
562 case *ast.GenDecl:
563 switch d.Tok {
564 case token.IMPORT:
565
566 for _, spec := range d.Specs {
567 if s, ok := spec.(*ast.ImportSpec); ok {
568 if import_, err := strconv.Unquote(s.Path.Value); err == nil {
569 r.imports[import_] = 1
570 if s.Name != nil && s.Name.Name == "." {
571 r.hasDotImp = true
572 }
573 }
574 }
575 }
576 case token.CONST, token.VAR:
577
578 r.readValue(d)
579 case token.TYPE:
580
581 if len(d.Specs) == 1 && !d.Lparen.IsValid() {
582
583
584
585
586
587 if s, ok := d.Specs[0].(*ast.TypeSpec); ok {
588 r.readType(d, s)
589 }
590 break
591 }
592 for _, spec := range d.Specs {
593 if s, ok := spec.(*ast.TypeSpec); ok {
594
595
596
597
598 fake := &ast.GenDecl{
599 Doc: d.Doc,
600
601
602
603
604
605 TokPos: s.Pos(),
606 Tok: token.TYPE,
607 Specs: []ast.Spec{s},
608 }
609 r.readType(fake, s)
610 }
611 }
612 }
613 }
614 }
615
616
617 r.readNotes(src.Comments)
618 if r.mode&PreserveAST == 0 {
619 src.Comments = nil
620 }
621 }
622
623 func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
624
625 r.filenames = make([]string, len(pkg.Files))
626 r.imports = make(map[string]int)
627 r.mode = mode
628 r.types = make(map[string]*namedType)
629 r.funcs = make(methodSet)
630 r.notes = make(map[string][]*Note)
631
632
633
634 i := 0
635 for filename := range pkg.Files {
636 r.filenames[i] = filename
637 i++
638 }
639 sort.Strings(r.filenames)
640
641
642 for _, filename := range r.filenames {
643 f := pkg.Files[filename]
644 if mode&AllDecls == 0 {
645 r.fileExports(f)
646 }
647 r.readFile(f)
648 }
649
650
651 for _, f := range pkg.Files {
652 for _, decl := range f.Decls {
653 if d, ok := decl.(*ast.FuncDecl); ok {
654 r.readFunc(d)
655 }
656 }
657 }
658 }
659
660
661
662
663 func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) *Func {
664 if f == nil || f.Decl == nil || f.Decl.Recv == nil || len(f.Decl.Recv.List) != 1 {
665 return f
666 }
667
668
669 newField := *f.Decl.Recv.List[0]
670 origPos := newField.Type.Pos()
671 _, origRecvIsPtr := newField.Type.(*ast.StarExpr)
672 newIdent := &ast.Ident{NamePos: origPos, Name: recvTypeName}
673 var typ ast.Expr = newIdent
674 if !embeddedIsPtr && origRecvIsPtr {
675 newIdent.NamePos++
676 typ = &ast.StarExpr{Star: origPos, X: newIdent}
677 }
678 newField.Type = typ
679
680
681 newFieldList := *f.Decl.Recv
682 newFieldList.List = []*ast.Field{&newField}
683
684
685 newFuncDecl := *f.Decl
686 newFuncDecl.Recv = &newFieldList
687
688
689 newF := *f
690 newF.Decl = &newFuncDecl
691 newF.Recv = recvString(typ)
692
693 newF.Level = level
694
695 return &newF
696 }
697
698
699
700 func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited embeddedSet) {
701 visited[typ] = true
702 for embedded, isPtr := range typ.embedded {
703
704
705
706
707
708 thisEmbeddedIsPtr := embeddedIsPtr || isPtr
709 for _, m := range embedded.methods {
710
711 if m.Level == 0 {
712 mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
713 }
714 }
715 if !visited[embedded] {
716 r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
717 }
718 }
719 delete(visited, typ)
720 }
721
722
723
724 func (r *reader) computeMethodSets() {
725 for _, t := range r.types {
726
727 if t.isStruct {
728
729 r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(embeddedSet))
730 } else {
731
732
733 }
734 }
735
736
737
738 for predecl := range r.shadowedPredecl {
739 for _, ityp := range r.fixmap[predecl] {
740 removeAnonymousField(predecl, ityp)
741 }
742 }
743 }
744
745
746
747
748
749
750 func (r *reader) cleanupTypes() {
751 for _, t := range r.types {
752 visible := r.isVisible(t.name)
753 predeclared := predeclaredTypes[t.name]
754
755 if t.decl == nil && (predeclared || visible && (t.isEmbedded || r.hasDotImp)) {
756
757
758
759
760
761
762 r.values = append(r.values, t.values...)
763
764 for name, f := range t.funcs {
765
766
767 r.funcs[name] = f
768 }
769
770 if !predeclared {
771 for name, m := range t.methods {
772
773 if _, found := r.funcs[name]; !found {
774 r.funcs[name] = m
775 }
776 }
777 }
778 }
779
780 if t.decl == nil || !visible {
781 delete(r.types, t.name)
782 }
783 }
784 }
785
786
787
788
789 type data struct {
790 n int
791 swap func(i, j int)
792 less func(i, j int) bool
793 }
794
795 func (d *data) Len() int { return d.n }
796 func (d *data) Swap(i, j int) { d.swap(i, j) }
797 func (d *data) Less(i, j int) bool { return d.less(i, j) }
798
799
800 func sortBy(less func(i, j int) bool, swap func(i, j int), n int) {
801 sort.Sort(&data{n, swap, less})
802 }
803
804 func sortedKeys(m map[string]int) []string {
805 list := make([]string, len(m))
806 i := 0
807 for key := range m {
808 list[i] = key
809 i++
810 }
811 sort.Strings(list)
812 return list
813 }
814
815
816
817 func sortingName(d *ast.GenDecl) string {
818 if len(d.Specs) == 1 {
819 if s, ok := d.Specs[0].(*ast.ValueSpec); ok {
820 return s.Names[0].Name
821 }
822 }
823 return ""
824 }
825
826 func sortedValues(m []*Value, tok token.Token) []*Value {
827 list := make([]*Value, len(m))
828 i := 0
829 for _, val := range m {
830 if val.Decl.Tok == tok {
831 list[i] = val
832 i++
833 }
834 }
835 list = list[0:i]
836
837 sortBy(
838 func(i, j int) bool {
839 if ni, nj := sortingName(list[i].Decl), sortingName(list[j].Decl); ni != nj {
840 return ni < nj
841 }
842 return list[i].order < list[j].order
843 },
844 func(i, j int) { list[i], list[j] = list[j], list[i] },
845 len(list),
846 )
847
848 return list
849 }
850
851 func sortedTypes(m map[string]*namedType, allMethods bool) []*Type {
852 list := make([]*Type, len(m))
853 i := 0
854 for _, t := range m {
855 list[i] = &Type{
856 Doc: t.doc,
857 Name: t.name,
858 Decl: t.decl,
859 Consts: sortedValues(t.values, token.CONST),
860 Vars: sortedValues(t.values, token.VAR),
861 Funcs: sortedFuncs(t.funcs, true),
862 Methods: sortedFuncs(t.methods, allMethods),
863 }
864 i++
865 }
866
867 sortBy(
868 func(i, j int) bool { return list[i].Name < list[j].Name },
869 func(i, j int) { list[i], list[j] = list[j], list[i] },
870 len(list),
871 )
872
873 return list
874 }
875
876 func removeStar(s string) string {
877 if len(s) > 0 && s[0] == '*' {
878 return s[1:]
879 }
880 return s
881 }
882
883 func sortedFuncs(m methodSet, allMethods bool) []*Func {
884 list := make([]*Func, len(m))
885 i := 0
886 for _, m := range m {
887
888 switch {
889 case m.Decl == nil:
890
891 case allMethods, m.Level == 0, !token.IsExported(removeStar(m.Orig)):
892
893
894 list[i] = m
895 i++
896 }
897 }
898 list = list[0:i]
899 sortBy(
900 func(i, j int) bool { return list[i].Name < list[j].Name },
901 func(i, j int) { list[i], list[j] = list[j], list[i] },
902 len(list),
903 )
904 return list
905 }
906
907
908
909
910 func noteBodies(notes []*Note) []string {
911 var list []string
912 for _, n := range notes {
913 list = append(list, n.Body)
914 }
915 return list
916 }
917
918
919
920
921
922 func IsPredeclared(s string) bool {
923 return predeclaredTypes[s] || predeclaredFuncs[s] || predeclaredConstants[s]
924 }
925
926 var predeclaredTypes = map[string]bool{
927 "any": true,
928 "bool": true,
929 "byte": true,
930 "comparable": true,
931 "complex64": true,
932 "complex128": true,
933 "error": true,
934 "float32": true,
935 "float64": true,
936 "int": true,
937 "int8": true,
938 "int16": true,
939 "int32": true,
940 "int64": true,
941 "rune": true,
942 "string": true,
943 "uint": true,
944 "uint8": true,
945 "uint16": true,
946 "uint32": true,
947 "uint64": true,
948 "uintptr": true,
949 }
950
951 var predeclaredFuncs = map[string]bool{
952 "append": true,
953 "cap": true,
954 "close": true,
955 "complex": true,
956 "copy": true,
957 "delete": true,
958 "imag": true,
959 "len": true,
960 "make": true,
961 "new": true,
962 "panic": true,
963 "print": true,
964 "println": true,
965 "real": true,
966 "recover": true,
967 }
968
969 var predeclaredConstants = map[string]bool{
970 "false": true,
971 "iota": true,
972 "nil": true,
973 "true": true,
974 }
975
View as plain text