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