Ejemplo n.º 1
0
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
}
Ejemplo n.º 2
0
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
	})
}
Ejemplo n.º 3
0
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
}