func handleFunctionCursor(cursor clang.Cursor) *Function { fname := cursor.Spelling() f := Function{ Name: fname, CName: fname, Comment: CleanDoxygenComment(cursor.RawCommentText()), IncludeFiles: newIncludeFiles(), Parameters: []FunctionParameter{}, } typ, err := typeFromClangType(cursor.ResultType()) if err != nil { panic(err) } f.ReturnType = typ numParam := int(cursor.NumArguments()) for i := 0; i < numParam; i++ { param := cursor.Argument(uint16(i)) p := FunctionParameter{ CName: param.DisplayName(), } typ, err := typeFromClangType(param.Type()) if err != nil { panic(err) } p.Type = typ p.Name = p.CName if p.Name == "" { p.Name = commonReceiverName(p.Type.GoName) } else { pns := strings.Split(p.Name, "_") for i := range pns { pns[i] = UpperFirstCharacter(pns[i]) } p.Name = LowerFirstCharacter(strings.Join(pns, "")) } if r := ReplaceGoKeywords(p.Name); r != "" { p.Name = r } f.Parameters = append(f.Parameters, p) } return &f }
func (h *HeaderFile) handleFile(cursor clang.Cursor) { /* TODO mark the enum https://github.com/go-clang/gen/issues/40 typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor, CXCursor parent, CXClientData client_data); as manually implemented */ // TODO report other enums like callbacks that they are not implemented https://github.com/go-clang/gen/issues/51 cursor.Visit(func(cursor, parent clang.Cursor) clang.ChildVisitResult { // Only handle code of the current file sourceFile, _, _, _ := cursor.Location().FileLocation() isCurrentFile := sourceFile.Name() == h.name if !strings.HasPrefix(sourceFile.Name(), h.dir) { return clang.ChildVisit_Continue } cname := cursor.Spelling() cnameIsTypeDef := false if parentCName := parent.Spelling(); parent.Kind() == clang.Cursor_TypedefDecl && parentCName != "" { cname = parentCName cnameIsTypeDef = true } switch cursor.Kind() { case clang.Cursor_EnumDecl: if cname == "" { break } e := handleEnumCursor(cursor, cname, cnameIsTypeDef) e.IncludeFiles.addIncludeFile(sourceFile.Name()) if _, ok := h.lookupEnum[e.Name]; !ok { h.lookupEnum[e.Name] = e h.lookupNonTypedefs["enum "+e.CName] = e.Name h.lookupEnum[e.CName] = e h.enums = append(h.enums, e) } case clang.Cursor_FunctionDecl: if !isCurrentFile { return clang.ChildVisit_Continue } f := handleFunctionCursor(cursor) if f != nil { f.IncludeFiles.addIncludeFile(sourceFile.Name()) h.functions = append(h.functions, f) } case clang.Cursor_StructDecl: if cname == "" { break } s := handleStructCursor(cursor, cname, cnameIsTypeDef) s.api = h.api s.IncludeFiles.addIncludeFile(sourceFile.Name()) if _, ok := h.lookupStruct[s.Name]; !ok { h.lookupStruct[s.Name] = s h.lookupNonTypedefs["struct "+s.CName] = s.Name h.lookupStruct[s.CName] = s h.structs = append(h.structs, s) } case clang.Cursor_TypedefDecl: underlyingType := cursor.TypedefDeclUnderlyingType().Spelling() underlyingStructType := strings.TrimSuffix(strings.TrimPrefix(underlyingType, "struct "), " *") if s, ok := h.lookupStruct[underlyingStructType]; ok && !s.CNameIsTypeDef && strings.HasPrefix(underlyingType, "struct "+s.CName) { // Sometimes the typedef is not a parent of the struct but a sibling sn := handleStructCursor(cursor, cname, true) sn.api = h.api sn.IncludeFiles.addIncludeFile(sourceFile.Name()) if sn.Comment == "" { sn.Comment = s.Comment } sn.Members = s.Members sn.Methods = s.Methods h.lookupStruct[sn.Name] = sn h.lookupNonTypedefs["struct "+sn.CName] = sn.Name h.lookupStruct[sn.CName] = sn // Update the lookups for the old struct h.lookupStruct[s.Name] = sn h.lookupStruct[s.CName] = sn for i, si := range h.structs { if si == s { h.structs[i] = sn break } } } else if underlyingType == "void *" { s := handleStructCursor(cursor, cname, true) s.api = h.api s.IncludeFiles.addIncludeFile(sourceFile.Name()) if _, ok := h.lookupStruct[s.Name]; !ok { h.lookupStruct[s.Name] = s h.lookupNonTypedefs["struct "+s.CName] = s.Name h.lookupStruct[s.CName] = s h.structs = append(h.structs, s) } } } return clang.ChildVisit_Recurse }) }
func handleEnumCursor(cursor clang.Cursor, cname string, cnameIsTypeDef bool) *Enum { e := Enum{ CName: cname, CNameIsTypeDef: cnameIsTypeDef, Comment: CleanDoxygenComment(cursor.RawCommentText()), IncludeFiles: newIncludeFiles(), Items: []EnumItem{}, } e.Name = TrimLanguagePrefix(e.CName) e.Receiver.Name = commonReceiverName(e.Name) e.Receiver.Type.GoName = e.Name e.Receiver.Type.CGoName = e.CName if cnameIsTypeDef { e.Receiver.Type.CGoName = e.CName } else { e.Receiver.Type.CGoName = "enum_" + e.CName } enumNamePrefix := e.Name enumNamePrefix = strings.TrimSuffix(enumNamePrefix, "Kind") enumNamePrefix = strings.SplitN(enumNamePrefix, "_", 2)[0] cursor.Visit(func(cursor, parent clang.Cursor) clang.ChildVisitResult { switch cursor.Kind() { case clang.Cursor_EnumConstantDecl: ei := EnumItem{ CName: cursor.Spelling(), Comment: CleanDoxygenComment(cursor.RawCommentText()), // TODO We are always using the same comment if there is none, see "TypeKind" https://github.com/go-clang/gen/issues/58 Value: cursor.EnumConstantDeclUnsignedValue(), } ei.Name = TrimLanguagePrefix(ei.CName) // Check if the first item has an enum prefix if len(e.Items) == 0 { eis := strings.SplitN(ei.Name, "_", 2) if len(eis) == 2 { enumNamePrefix = "" } } // Add the enum prefix to the item if enumNamePrefix != "" { ei.Name = strings.TrimSuffix(ei.Name, enumNamePrefix) if !strings.HasPrefix(ei.Name, enumNamePrefix) { ei.Name = enumNamePrefix + "_" + ei.Name } } e.Items = append(e.Items, ei) default: panic(cursor.Kind()) } return clang.ChildVisit_Continue }) if strings.HasSuffix(e.Name, "Error") { e.UnderlyingType = "int32" } else { e.UnderlyingType = "uint32" } return &e }