func (fa *facade) Underlying() types.Type {
	return fa.typ().Underlying()
}
Underlying returns the underlying type of a type.
package aster
import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"sort"
	"strings"
)
type Facade interface {
	facadeIdentify()  
	FileSet() *token.FileSet
	FormatNode(ast.Node) (string, error)
	PackageInfo() *PackageInfo
	File() *File
	Node() ast.Node
	Ident() *ast.Ident
	Object() types.Object
	ObjKind() ObjKind
	TypKind() TypKind
	Id() string
	Name() string
	Doc() string
	SetDoc(text string) bool
	Exported() bool
	String() string
	Underlying() types.Type
	IsAlias() bool
	NumMethods() int
	Method(i int) Facade
	AssertableTo(T Facade) bool
	AssignableTo(T Facade) bool
	ConvertibleTo(T Facade) bool
	Implements(iface Facade, usePtr bool) bool
	Elem() types.Type
	Key() types.Type
	Len() int64
	ChanDir() types.ChanDir
	BasicInfo() types.BasicInfo
	BasicKind() types.BasicKind
	IsMethod() bool
	Params() *types.Tuple
	Recv() *types.Var
	Results() *types.Tuple
	Variadic() bool
	Body() (string, error)
	CoverBody(body string) error
	NumFields() int
	Field(i int) *StructField
	FieldByName(name string) (field *StructField, found bool)
	IfaceEmbeddedType(i int) Facade
	IfaceEmpty() bool
	IfaceExplicitMethod(i int) Facade
	IfaceNumEmbeddeds() int
	IfaceNumExplicitMethods() int
}
type facade struct {
	fset         *token.FileSet
	file         *File
	node         ast.Node
	obj          types.Object
	pkg          *PackageInfo
	ident        *ast.Ident
	doc          *ast.CommentGroup
	structFields []*StructField  
}
var _ Facade = (*facade)(nil)
func (fa *facade) facadeIdentify() {}
func (fa *facade) mustGetFacadeByObj(obj types.Object) *facade {
	facade, idx := fa.pkg.getFacadeByObj(obj)
	if idx < 0 {
		panic(fmt.Sprintf("aster: mustGetFacadeByObj can't find %s", obj.String()))
	}
	return facade
}
func (fa *facade) mustGetFacadeByTyp(typ types.Type) *facade {
	facade, idx := fa.pkg.getFacadeByTyp(typ)
	if idx < 0 {
		panic(fmt.Sprintf("aster: mustGetFacadeByTyp can't find %s", typ.String()))
	}
	return facade
}
func (fa *facade) FileSet() *token.FileSet {
	return fa.fset
}
func (fa *facade) FormatNode(node ast.Node) (string, error) {
	return fa.PackageInfo().FormatNode(node)
}
func (fa *facade) PackageInfo() *PackageInfo {
	return fa.pkg
}
func (fa *facade) File() *File {
	return fa.file
}
func (fa *facade) Node() ast.Node {
	return fa.node
}
func (fa *facade) Ident() *ast.Ident {
	return fa.ident
}
func (fa *facade) Object() types.Object {
	return fa.obj
}
func (fa *facade) ObjKind() ObjKind {
	return GetObjKind(fa.obj)
}
func (fa *facade) TypKind() TypKind {
	return GetTypKind(fa.typ())
}
func (fa *facade) typKind() TypKind {
	if fa.ObjKind() == Bad {
		return Invalid
	}
	return GetTypKind(fa.obj.Type())
}
func (fa *facade) typ() types.Type {
	if fa.typKind() == named {
		return fa.obj.Type().Underlying()
	}
	return fa.obj.Type()
}
func (fa *facade) Id() string { return fa.obj.Id() }
func (fa *facade) Name() string {
	return fa.ident.Name
}
func (fa *facade) Doc() string {
	return fa.doc.Text()
}
func (fa *facade) SetDoc(text string) bool {
	if fa.doc == nil || len(fa.doc.List) == 0 {
		doc := newCommentGroup()
		common := doc.List[0]
		var found bool
		_, nodes, _ := fa.file.pathEnclosingInterval(fa.ident.Pos(), fa.ident.End())
	L:
		for _, node := range nodes {
			switch decl := node.(type) {
			case *ast.FuncDecl:
				common.Slash = decl.Pos() - 1
				decl.Doc = doc
				found = true
				break L
			case *ast.Field:
				break L
			case *ast.GenDecl:
				if found {
					if decl.Lparen == 0 {
						n := 0
						switch decl.Tok {
						case token.IMPORT:
							n = len("IMPORT")
						case token.CONST:
							n = len("CONST")
						case token.TYPE:
							n = len("TYPE")
						case token.VAR:
							n = len("VAR")
						}
						common.Slash -= token.Pos(n + 1)
					}
				} else {
					common.Slash = decl.Pos() - 1
					decl.Doc = doc
					found = true
				}
				break L
			case *ast.TypeSpec:
				common.Slash = decl.Pos() - 1
				decl.Doc = doc
				found = true
				continue L
			case *ast.ValueSpec:
				common.Slash = decl.Pos() - 1
				decl.Doc = doc
				found = true
				continue L
			case *ast.Ident:
				continue L
			default:
				break L
			}
		}
		if !found {
			return false
		}
		fa.doc = doc
		fa.file.appendComment(doc)
	}
	fa.doc.List = fa.doc.List[len(fa.doc.List)-1:]
	doc := fa.doc.List[0]
	doc.Text = cleanDoc(text)
	return true
}
func (f *File) appendComment(doc *ast.CommentGroup) {
	f.Comments = append(f.Comments, doc)
	sort.Sort(fileComments(f.Comments))
}
type fileComments []*ast.CommentGroup
func (c fileComments) Len() int {
	return len(c)
}
func (c fileComments) Less(i, j int) bool {
	return c[i].Pos() < c[j].Pos()
}
func (c fileComments) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func newCommentGroup() *ast.CommentGroup {
	common := new(ast.Comment)
	common.Text = "//"
	return &ast.CommentGroup{List: []*ast.Comment{common}}
}
func cleanDoc(text string) string {
	text = strings.TrimSpace(text)
	text = strings.Trim(text, "//")
	text = strings.TrimLeft(text, "/**")
	text = strings.TrimRight(text, "**/")
	text = strings.TrimLeft(text, "/*")
	text = strings.TrimRight(text, "*/")
	text = "// " + strings.Replace(text, "\n", "\n// ", -1)
	return text
}
func (fa *facade) Exported() bool { return fa.obj.Exported() }
func (fa *facade) String() string { return fa.pkg.Preview(fa.ident) }