// 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 newValue(decl *ast.GenDecl) *Value { v := new(Value) v.Doc = doc.CommentText(decl.Doc) decl.Doc = nil // count names and figure out type n := 0 for _, spec := range decl.Specs { vspec := spec.(*ast.ValueSpec) for _, name := range vspec.Names { if ast.IsExported(name.Name) { n++ } } if v.Type == "" { t := typeAsString(vspec.Type) if t != "" && ast.IsExported(t) { v.Type = t } } } if n == 0 { return nil } // collect names v.Names = make([]string, n) i := 0 for _, spec := range decl.Specs { vspec := spec.(*ast.ValueSpec) for _, name := range vspec.Names { if !ast.IsExported(name.Name) { continue } v.Names[i] = name.Name i++ } } v.Decl = decl return v }
// 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 info.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() // look for anonymous fields that might contribute methods var list []*ast.Field list, typ.isStruct = fields(spec.Type) for _, field := range list { if len(field.Names) == 0 { // anonymous field - add corresponding field type to typ n, imp := baseTypeName(field.Type) if imp { // imported type - we don't handle this case // at the moment return } if embedded := r.lookupType(n); embedded != nil { _, ptr := field.Type.(*ast.StarExpr) typ.addEmbeddedType(embedded, ptr) } } } }
// oneLineValueGenDecl prints a var or const declaration as a single line. func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) { decl.Doc = nil dotDotDot := "" if len(decl.Specs) > 1 { dotDotDot = " ..." } // Find the first relevant spec. for i, spec := range decl.Specs { valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl. if !isExported(valueSpec.Names[0].Name) { continue } typ := "" if valueSpec.Type != nil { typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type)) } val := "" if i < len(valueSpec.Values) && valueSpec.Values[i] != nil { val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i])) } pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot) break } }
// 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 }