// readType processes a type declaration. // func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) { typ := r.lookupType(spec.Name.Name) if typ == nil { return // no name or blank name - ignore the type } // A type should be added at most once, so typ.decl // should be nil - if it is not, simply overwrite it. typ.decl = decl // compute documentation doc := spec.Doc spec.Doc = nil // doc consumed - remove from AST if doc == nil { // no doc associated with the spec, use the declaration doc, if any doc = decl.Doc } decl.Doc = nil // doc consumed - remove from AST typ.doc = doc.Text() // record anonymous fields (they may contribute methods) // (some fields may have been recorded already when filtering // exports, but that's ok) var list []*ast.Field list, typ.isStruct = fields(spec.Type) for _, field := range list { if len(field.Names) == 0 { r.recordAnonymousField(typ, field.Type) } } }
func (p *printer) genDecl(d *ast.GenDecl) { p.setComment(d.Doc) p.print(d.Pos(), d.Tok, blank) if d.Lparen.IsValid() { // group of parenthesized declarations p.print(d.Lparen, token.LPAREN) if n := len(d.Specs); n > 0 { p.print(indent, formfeed) if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) { // two or more grouped const/var declarations: // determine if the type column must be kept keepType := keepTypeColumn(d.Specs) var line int for i, s := range d.Specs { if i > 0 { p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0) } p.recordLine(&line) p.valueSpec(s.(*ast.ValueSpec), keepType[i]) } } else { var line int for i, s := range d.Specs { if i > 0 { p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0) } p.recordLine(&line) p.spec(s, n, false) } } p.print(unindent, formfeed) } p.print(d.Rparen, token.RPAREN) } else { // single declaration p.spec(d.Specs[0], 1, true) } }
// readValue processes a const or var declaration. // func (r *reader) readValue(decl *ast.GenDecl) { // determine if decl should be associated with a type // Heuristic: For each typed entry, determine the type name, if any. // If there is exactly one type name that is sufficiently // frequent, associate the decl with the respective type. domName := "" domFreq := 0 prev := "" n := 0 for _, spec := range decl.Specs { s, ok := spec.(*ast.ValueSpec) if !ok { continue // should not happen, but be conservative } name := "" switch { case s.Type != nil: // a type is present; determine its name if n, imp := baseTypeName(s.Type); !imp { name = n } case decl.Tok == token.CONST: // no type is present but we have a constant declaration; // use the previous type name (w/o more type information // we cannot handle the case of unnamed variables with // initializer expressions except for some trivial cases) name = prev } if name != "" { // entry has a named type if domName != "" && domName != name { // more than one type name - do not associate // with any type domName = "" break } domName = name domFreq++ } prev = name n++ } // nothing to do w/o a legal declaration if n == 0 { return } // determine values list with which to associate the Value for this decl values := &r.values const threshold = 0.75 if domName != "" && r.isVisible(domName) && domFreq >= int(float64(len(decl.Specs))*threshold) { // typed entries are sufficiently frequent if typ := r.lookupType(domName); typ != nil { values = &typ.values // associate with that type } } *values = append(*values, &Value{ Doc: decl.Doc.Text(), Names: specNames(decl.Specs), Decl: decl, order: len(*values), }) decl.Doc = nil // doc consumed - remove from AST }