func getQmlObjectStructs(goFile string) ([]object, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, goFile, nil, 0)
	if err != nil {
		return nil, err
	}
	usingQamel := false
	importName := qamelImportName
	for _, importSpec := range f.Imports {
		importPath := strings.Trim(importSpec.Path.Value, `"`)
		if importPath != qamelImportPath {
			continue
		}
		if importSpec.Name != nil {
			importName = importSpec.Name.Name
		}
		usingQamel = true
	}
	if !usingQamel {
		return []object{}, nil
	}
	// Traverse file tree to find struct that embedding QmlObject
	var result []object
	embeddedName := fmt.Sprintf("%s.%s", importName, qamelObjectName)
	ast.Inspect(f, func(node ast.Node) bool {
		// Make sure this node is a declaration of `type`
		typeNode, isTypeSpec := node.(*ast.TypeSpec)
		if !isTypeSpec {
			return true
		}
		// Make sure this type is declaring a struct
		structNode, isStruct := typeNode.Type.(*ast.StructType)
		if !isStruct {
			return false
		}
		// Make sure this struct has fields
		if structNode.Fields == nil || len(structNode.Fields.List) == 0 {
			return false
		}
		// Check this struck embedding QmlObject
		embeddingQamel := false
		for _, field := range structNode.Fields.List {
			selector, isSelector := field.Type.(*ast.SelectorExpr)
			if !isSelector {
				continue
			}
			selectorValue := fmt.Sprintf("%s.%s", selector.X, selector.Sel.Name)
			if selectorValue == embeddedName {
				embeddingQamel = true
				break
			}
		}
		if !embeddingQamel {
			return false
		}
		result = append(result, object{
			name:        typeNode.Name.Name,
			dirPath:     fp.Dir(goFile),
			fileName:    goFile,
			packageName: f.Name.Name,
			structNode:  structNode,
		})
		return false
	})
	return result, nil
}
getQmlObjectStruct fetch structs that embedded with qamel.QmlObject inside specified Go file
package generator
import (
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	fp "path/filepath"
	"reflect"
	"regexp"
	"strings"
	"github.com/go-qamel/qamel/internal/config"
)
var (
	qamelImportName = "qamel"
	qamelImportPath = "github.com/go-qamel/qamel"
	qamelObjectName = "QmlObject"
	rxNumber = regexp.MustCompile(`\d`)
	rxSymbol = regexp.MustCompile(`[^A-Za-z0-9]`)
)
type object struct {
	name         string
	dirPath      string
	fileName     string
	packageName  string
	structNode   *ast.StructType
	constructors []objectMethod
	properties   []objectMember
	signals      []objectMethod
	slots        []objectMethod
}
type objectMember struct {
	name       string
	memberType string
}
type objectMethod struct {
	name       string
	parameters []objectMember
	returns    []objectMember
}
func CreateQmlObjectCode(profile config.Profile, projectDir string, buildTags ...string) []error {
	if !dirExists(projectDir) {
		err := fmt.Errorf("directory %s doesn't exist", projectDir)
		return []error{err}
	}
	subDirs, err := getSubDirs(projectDir)
	if err != nil {
		return []error{err}
	}
	var goFiles []string
	buildCtx := build.Default
	buildCtx.BuildTags = append([]string{}, buildTags...)
	for _, dir := range subDirs {
		dirPkg, err := buildCtx.ImportDir(dir, 0)
		if err != nil {
			continue
		}
		for _, goFile := range dirPkg.GoFiles {
			goFiles = append(goFiles, fp.Join(dir, goFile))
		}
	}
	var qmlObjects []object
	for _, goFile := range goFiles {
		objects, err := getQmlObjectStructs(goFile)
		if err != nil {
			return []error{err}
		}
		qmlObjects = append(qmlObjects, objects...)
	}
	var errors []error
	for i, obj := range qmlObjects {
		tmpObj, tmpErrors := parseQmlObject(obj)
		errors = append(errors, tmpErrors...)
		qmlObjects[i] = tmpObj
	}
	if len(errors) > 0 {
		return errors
	}
	mapDirPackage := map[string]string{}
	for _, obj := range qmlObjects {
		mapDirPackage[obj.dirPath] = obj.packageName
		err = createCppHeaderFile(obj)
		if err != nil {
			return []error{err}
		}
		err = createCppFile(profile.Moc, obj)
		if err != nil {
			return []error{err}
		}
		err = createGoFile(obj)
		if err != nil {
			return []error{err}
		}
	}
	for dir, packageName := range mapDirPackage {
		err = CreateCgoFile(profile, dir, packageName)
		if err != nil {
			return []error{err}
		}
	}
	return nil
}