func documentFunction(f *ast.File, pkg *genutil.Package, value ast.Expr, prev token.Pos, cur token.Pos) *funcDoc { fileScope := pkg.Info().Scopes[f] val := pkg.Info().Types[value] ftyp := val.Type for { named, ok := ftyp.(*types.Named) if !ok { break } ftyp = named.Underlying() } if sel, ok := value.(*ast.SelectorExpr); ok { x := astutil.Ident(sel.X) obj := fileScope.Lookup(x) if pkgName, ok := obj.(*types.PkgName); ok { expr := astutil.Ident(sel.Sel) return &funcDoc{ decl: fmt.Sprintf("%s", ftyp), alias: pkgName.Pkg().Path() + "." + expr, } } return nil } if _, ok := value.(*ast.Ident); ok { if comments := commentsBetween(f, prev, cur); comments != "" { return &funcDoc{ doc: comments, decl: fmt.Sprintf("%s", ftyp), } } return nil } return nil }
func (s *Stats) typeStats(typs []*doc.Type, total *int, score *int) { for _, v := range typs { *total += typeScore if v.Doc != "" { *score += typeScore } else { s.Undocumented = append(s.Undocumented, &Undocumented{ Kind: Type, Name: v.Name, Node: v.Decl, }) } // Fields var k Kind ts := v.Decl.Specs[0].(*ast.TypeSpec) var fields []*ast.Field switch s := ts.Type.(type) { case *ast.StructType: fields = s.Fields.List k = Field case *ast.InterfaceType: fields = s.Methods.List k = IMethod } fs := k.DocScore() for _, f := range fields { *total += fs if f.Doc != nil || f.Comment != nil { *score += fs } else { var name string if len(f.Names) > 0 { name = astutil.Ident(f.Names[0]) } else { // Embedded field name = astutil.Ident(f.Type) if name[0] == '*' { name = name[1:] } if dot := strings.IndexByte(name, '.'); dot >= 0 { name = name[dot+1:] } } s.Undocumented = append(s.Undocumented, &Undocumented{ Kind: k, Name: name, Type: v.Name, Node: f, }) } } s.valueStats(Const, v.Consts, total, score) s.valueStats(Var, v.Vars, total, score) s.funcStats("", v.Funcs, total, score) s.funcStats(v.Name, v.Methods, total, score) } }
func (s *Stats) valueStats(k Kind, values []*doc.Value, total *int, score *int) { for _, v := range values { if v.Doc != "" { // There's a comment just before the declaration. // Consider all the values documented c := len(v.Decl.Specs) * valueScore *score += c *total += c } else { // Check every value declared in this group for _, spec := range v.Decl.Specs { *total += valueScore sp := spec.(*ast.ValueSpec) if sp.Doc != nil || sp.Comment != nil { *score += valueScore } else { for _, n := range sp.Names { s.Undocumented = append(s.Undocumented, &Undocumented{ Kind: k, Name: astutil.Ident(n), Node: spec, }) } } } } } }
func (p *Package) scopeParameters(node interface{}) (string, map[string]struct{}) { var scope string var ignored map[string]struct{} ignore := func(x string) { if ignored == nil { ignored = make(map[string]struct{}) } ignored[x] = struct{}{} } switch n := node.(type) { case *ast.FuncDecl: ignore(n.Name.Name) if n.Recv != nil { scope = astutil.Ident(n.Recv.List[0].Type) if scope != "" && scope[0] == '*' { scope = scope[1:] } } case *ast.GenDecl: for _, spec := range n.Specs { switch s := spec.(type) { case *ast.TypeSpec: scope = s.Name.Name ignore(scope) case *ast.ValueSpec: for _, name := range s.Names { ignore(name.Name) } } } } return scope, ignored }
func FuncReceiver(fn *ast.FuncDecl) string { if fn.Recv != nil { recv := astutil.Ident(fn.Recv.List[0].Type) if recv[0] == '*' { recv = recv[1:] } return recv } return "" }
func extractGoFunc(messages messageMap, fset *token.FileSet, f *ast.File, fn *Function) error { calls, err := astutil.Calls(fset, f, fn.Name) if err != nil { return err } n := fn.Start if fn.Context { n++ } var message *Message var position *token.Position for _, c := range calls { if fn.Plural { if len(c.Args) < n+3 { log.Debugf("Skipping plural function %s (%v) - not enough arguments", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } slit, spos := astutil.StringLiteral(fset, c.Args[n]) if slit == "" || spos == nil { log.Debugf("Skipping first argument to plural function %s (%v) - not a literal", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } plit, ppos := astutil.StringLiteral(fset, c.Args[n+1]) if plit == "" || ppos == nil { log.Debugf("Skipping second argument to plural function %s (%v) - not a literal", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } message = &Message{ Singular: slit, Plural: plit, } position = spos } else { if len(c.Args) < n+1 { log.Debugf("Skipping singular function %s (%v) - not enough arguments", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } lit, pos := astutil.StringLiteral(fset, c.Args[n]) if lit == "" || pos == nil { log.Debugf("Skipping argument to singular function %s (%v) - not a literal", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } message = &Message{ Singular: lit, } position = pos } if message != nil && position != nil { if fn.Context { ctx, cpos := astutil.StringLiteral(fset, c.Args[fn.Start]) if ctx == "" || cpos == nil { log.Debugf("Skipping argument to context function %s (%v) - empty context", astutil.Ident(c.Fun), fset.Position(c.Pos())) continue } message.Context = ctx } if err := messages.Add(message, position, comments(fset, f, position)); err != nil { return err } } } return nil }