Beispiel #1
0
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
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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,
						})
					}
				}
			}
		}
	}
}
Beispiel #4
0
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
}
Beispiel #5
0
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 ""
}
Beispiel #6
0
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
}