// addFile adds the AST for a source file to the docReader. // Adding the same AST multiple times is a no-op. // func (doc *docReader) addFile(src *ast.File) { // add package documentation if src.Doc != nil { doc.addDoc(src.Doc) src.Doc = nil // doc consumed - remove from ast.File node } // add all declarations for _, decl := range src.Decls { doc.addDecl(decl) } // collect BUG(...) comments for _, c := range src.Comments { text := c.List[0].Text if m := bug_markers.FindStringIndex(text); m != nil { // found a BUG comment; maybe empty if btxt := text[m[1]:]; bug_content.MatchString(btxt) { // non-empty BUG comment; collect comment without BUG prefix list := copyCommentList(c.List) list[0].Text = text[m[1]:] doc.bugs = append(doc.bugs, &ast.CommentGroup{list}) } } } src.Comments = nil // consumed unassociated comments - remove from ast.File node }
// addFile adds the AST for a source file to the docReader. // Adding the same AST multiple times is a no-op. // func (doc *docReader) addFile(src *ast.File) { // add package documentation if src.Doc != nil { // TODO(gri) This won't do the right thing if there is more // than one file with package comments. Consider // using ast.MergePackageFiles which handles these // comments correctly (but currently looses BUG(...) // comments). doc.doc = src.Doc src.Doc = nil // doc consumed - remove from ast.File node } // add all declarations for _, decl := range src.Decls { doc.addDecl(decl) } // collect BUG(...) comments for c := src.Comments; c != nil; c = c.Next { text := c.List[0].Text cstr := string(text) if m := bug_markers.ExecuteString(cstr); len(m) > 0 { // found a BUG comment; maybe empty if bstr := cstr[m[1]:]; bug_content.MatchString(bstr) { // non-empty BUG comment; collect comment without BUG prefix list := copyCommentList(c.List) list[0].Text = text[m[1]:] doc.bugs.Push(&ast.CommentGroup{list, nil}) } } } src.Comments = nil // consumed unassociated comments - remove from ast.File node }
// readFile adds the AST for a source file to the reader. // func (r *reader) readFile(src *ast.File) { // add package documentation if src.Doc != nil { r.readDoc(src.Doc) src.Doc = nil // doc consumed - remove from AST } // add all declarations for _, decl := range src.Decls { switch d := decl.(type) { case *ast.GenDecl: switch d.Tok { case token.IMPORT: // imports are handled individually for _, spec := range d.Specs { if s, ok := spec.(*ast.ImportSpec); ok { if import_, err := strconv.Unquote(s.Path.Value); err == nil { r.imports[import_] = 1 } } } case token.CONST, token.VAR: // constants and variables are always handled as a group r.readValue(d) case token.TYPE: // types are handled individually for _, spec := range d.Specs { if s, ok := spec.(*ast.TypeSpec); ok { // use an individual (possibly fake) declaration // for each type; this also ensures that each type // gets to (re-)use the declaration documentation // if there's none associated with the spec itself fake := &ast.GenDecl{ d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{s}, token.NoPos, } r.readType(fake, s) } } } case *ast.FuncDecl: r.readFunc(d) } } // collect BUG(...) comments for _, c := range src.Comments { text := c.List[0].Text if m := bug_markers.FindStringIndex(text); m != nil { // found a BUG comment; maybe empty if btxt := text[m[1]:]; bug_content.MatchString(btxt) { // non-empty BUG comment; collect comment without BUG prefix list := append([]*ast.Comment(nil), c.List...) // make a copy list[0].Text = text[m[1]:] r.bugs = append(r.bugs, (&ast.CommentGroup{list}).Text()) } } } src.Comments = nil // consumed unassociated comments - remove from AST }
func mergeASTFile(dst, src *ast.File) *ast.File { if dst == nil { return src } if dst.Doc != nil { dst.Doc = src.Doc } dst.Decls = append(dst.Decls, src.Decls...) return dst }
// readFile adds the AST for a source file to the reader. // func (r *reader) readFile(src *ast.File) { // add package documentation if src.Doc != nil { r.readDoc(src.Doc) src.Doc = nil // doc consumed - remove from AST } // add all declarations for _, decl := range src.Decls { switch d := decl.(type) { case *ast.GenDecl: switch d.Tok { case token.IMPORT: // imports are handled individually for _, spec := range d.Specs { if s, ok := spec.(*ast.ImportSpec); ok { if import_, err := strconv.Unquote(s.Path.Value); err == nil { r.imports[import_] = 1 } } } case token.CONST, token.VAR: // constants and variables are always handled as a group r.readValue(d) case token.TYPE: // types are handled individually if len(d.Specs) == 1 && !d.Lparen.IsValid() { // common case: single declaration w/o parentheses // (if a single declaration is parenthesized, // create a new fake declaration below, so that // go/doc type declarations always appear w/o // parentheses) if s, ok := d.Specs[0].(*ast.TypeSpec); ok { r.readType(d, s) } break } for _, spec := range d.Specs { if s, ok := spec.(*ast.TypeSpec); ok { // use an individual (possibly fake) declaration // for each type; this also ensures that each type // gets to (re-)use the declaration documentation // if there's none associated with the spec itself fake := &ast.GenDecl{ Doc: d.Doc, // don't use the existing TokPos because it // will lead to the wrong selection range for // the fake declaration if there are more // than one type in the group (this affects // src/cmd/godoc/godoc.go's posLink_urlFunc) TokPos: s.Pos(), Tok: token.TYPE, Specs: []ast.Spec{s}, } r.readType(fake, s) } } } case *ast.FuncDecl: r.readFunc(d) } } // collect BUG(...) comments for _, c := range src.Comments { text := c.List[0].Text if m := bug_markers.FindStringIndex(text); m != nil { // found a BUG comment; maybe empty if btxt := text[m[1]:]; bug_content.MatchString(btxt) { // non-empty BUG comment; collect comment without BUG prefix list := append([]*ast.Comment(nil), c.List...) // make a copy list[0].Text = text[m[1]:] r.bugs = append(r.bugs, (&ast.CommentGroup{List: list}).Text()) } } } src.Comments = nil // consumed unassociated comments - remove from AST }
// readFile adds the AST for a source file to the reader. // func (r *reader) readFile(src *ast.File) { // add package documentation if src.Doc != nil { r.readDoc(src.Doc) src.Doc = nil // doc consumed - remove from AST } // add all declarations for _, decl := range src.Decls { switch d := decl.(type) { case *ast.GenDecl: switch d.Tok { case token.IMPORT: // imports are handled individually for _, spec := range d.Specs { if s, ok := spec.(*ast.ImportSpec); ok { if import_, err := strconv.Unquote(s.Path.Value); err == nil { r.imports[import_] = 1 } } } case token.CONST, token.VAR: // constants and variables are always handled as a group r.readValue(d) case token.TYPE: // types are handled individually if len(d.Specs) == 1 && !d.Lparen.IsValid() { // common case: single declaration w/o parentheses // (if a single declaration is parenthesized, // create a new fake declaration below, so that // go/doc type declarations always appear w/o // parentheses) if s, ok := d.Specs[0].(*ast.TypeSpec); ok { r.readType(d, s) } break } for _, spec := range d.Specs { if s, ok := spec.(*ast.TypeSpec); ok { // use an individual (possibly fake) declaration // for each type; this also ensures that each type // gets to (re-)use the declaration documentation // if there's none associated with the spec itself fake := &ast.GenDecl{ Doc: d.Doc, // don't use the existing TokPos because it // will lead to the wrong selection range for // the fake declaration if there are more // than one type in the group (this affects // src/cmd/godoc/godoc.go's posLink_urlFunc) TokPos: s.Pos(), Tok: token.TYPE, Specs: []ast.Spec{s}, } r.readType(fake, s) } } } case *ast.FuncDecl: r.readFunc(d) } } // collect MARKER(...): annotations r.readNotes(src.Comments) src.Comments = nil // consumed unassociated comments - remove from AST }