コード例 #1
0
ファイル: typevisitor.go プロジェクト: grmartin/godoc2puml
func toSourcePos(fset *token.FileSet, node ast.Node) SourcePos {
	file := fset.File(node.Pos())
	start := file.Offset(node.Pos())
	end := file.Offset(node.End())
	return SourcePos(fmt.Sprintf("%s:#%d,#%d", file.Name(), start, end))
}
コード例 #2
0
ファイル: parser.go プロジェクト: grmartin/godoc2puml
func typeGoString(expr ast.Node) string {
	if expr == nil {
		return ""
	}
	// TODO: refactor using go/printer
	switch expr := expr.(type) {
	case *ast.Ident:
		return expr.String()
	case *ast.ArrayType:
		return "[]" + typeGoString(expr.Elt)
	case *ast.StarExpr:
		return "*" + typeGoString(expr.X)
	case *ast.SelectorExpr:
		return typeGoString(expr.X) + "." + expr.Sel.String()
	case *ast.FuncType:
		pre := "func(" + typeGoString(expr.Params) + ")"
		if expr.Results == nil || expr.Results.List == nil {
			return pre
		}
		post := typeGoString(expr.Results)
		if len(expr.Results.List) == 1 {
			return pre + " " + post
		}
		return pre + " (" + post + ")"
	case *ast.FieldList:
		if expr == nil {
			return ""
		}
		var buf bytes.Buffer
		for i, field := range expr.List {
			if i != 0 {
				buf.WriteString(", ")
			}
			if len(field.Names) == 0 {
				buf.WriteString(typeGoString(field.Type))
			}
			for i, name := range field.Names {
				if i != 0 {
					buf.WriteString(", ")
				}
				buf.WriteString(name.String())
				buf.WriteString(" ")
				buf.WriteString(typeGoString(field.Type))
			}
		}
		return buf.String()
	case *ast.MapType:
		return "map[" + typeGoString(expr.Key) + "]" + typeGoString(expr.Value)
	case *ast.InterfaceType:
		return "interface{" + typeGoString(expr.Methods) + "}"
	case *ast.StructType:
		return "struct{" + typeGoString(expr.Fields) + "}"
	case *ast.ChanType:
		switch expr.Dir {
		case ast.SEND:
			return "chan<- " + typeGoString(expr.Value)
		case ast.RECV:
			return "<-chan " + typeGoString(expr.Value)
		default:
			return "chan " + typeGoString(expr.Value)
		}
	case *ast.Ellipsis:
		return "..." + typeGoString(expr.Elt)
	default:
		panic(fmt.Errorf("%#v", expr))
	}
}
コード例 #3
0
ファイル: typevisitor.go プロジェクト: grmartin/godoc2puml
func (v *typeVisitor) elementType(expr ast.Node) string {
	if expr == nil {
		return ""
	}
	p := v.astPackage
	f := v.astFile
	switch expr := expr.(type) {
	case *ast.Ident:
		name := expr.String()
		if name == "error" || isPrimitive(name) {
			return name
		}
		for _, f := range p.Files {
			if f.Scope.Lookup(name) != nil {
				return v.pkg.Name + "." + name
			}
		}
		// TODO: refactor
		for _, imp := range f.Imports {
			local := imp.Name
			if local == nil || local.String() != `.` {
				continue
			}
			importPath, _ := strconv.Unquote(imp.Path.Value)
			if local == nil && path.Base(importPath) != name {
				continue
			}

			buildPkg, err := build.Import(importPath, ".", build.FindOnly)
			if err != nil {
				log.Printf("%#v", err)
				continue
			}
			dir := buildPkg.Dir

			fset := token.NewFileSet()
			pkgs, err := parser.ParseDir(fset, dir, func(fi os.FileInfo) bool {
				return !fi.IsDir() && !strings.HasSuffix(fi.Name(), "_test.go")
			}, 0)
			if err != nil {
				log.Printf("%#v", err)
				continue
			}
			for _, pkg := range pkgs {
				for _, f := range pkg.Files {
					if f.Scope.Lookup(name) == nil {
						continue
					}
					break
				}
				break // break?
			}
			return importPath + "." + name
		}
		log.Printf("can't resolve name", name)
		return name
	case *ast.ArrayType:
		return v.elementType(expr.Elt)
	case *ast.StarExpr:
		return v.elementType(expr.X)
	case *ast.SelectorExpr:
		name := expr.X.(*ast.Ident).String()
		for _, imp := range f.Imports {
			local := imp.Name
			if local != nil && local.String() != name {
				continue
			}
			importPath, _ := strconv.Unquote(imp.Path.Value)
			if local == nil && path.Base(importPath) != name {
				continue
			}
			name = importPath
			break
		}
		return name + "." + expr.Sel.String()
	case *ast.FuncType:
		return strings.TrimSpace("func(" + v.elementType(expr.Params) + ") " + v.elementType(expr.Results))
	case *ast.FieldList:
		if expr == nil {
			return ""
		}
		var buf bytes.Buffer
		for _, field := range expr.List {
			buf.WriteString(v.elementType(field.Type))
		}
		return buf.String()
	case *ast.MapType:
		return "map[" + v.elementType(expr.Key) + "]" + v.elementType(expr.Value)
	case *ast.InterfaceType:
		return "interface {" + v.elementType(expr.Methods) + "}"
	case *ast.StructType:
		return "struct {" + v.elementType(expr.Fields) + "}"
	case *ast.ChanType:
		switch expr.Dir {
		case ast.SEND:
			return "chan<- " + v.elementType(expr.Value)
		case ast.RECV:
			return "<-chan " + v.elementType(expr.Value)
		default:
			return "chan " + v.elementType(expr.Value)
		}
	case *ast.Ellipsis:
		return "..." + v.elementType(expr.Elt)
	default:
		panic(fmt.Errorf("%#v", expr))
	}
}