void ParseClassCursor(Cursor cursor)
        {
            string className = cursor.Spelling;
            string fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor);

            ClassDefinition @class;
            if (project.ClassDefinitions.TryGetValue(fullyQualifiedName, out @class))
            {
                if (@class.IsParsed) return;

                @class.Parent = _context.Class;
            }
            else
            {
                switch(cursor.Kind)
                {
                    case CursorKind.ClassTemplate:
                        @class = new ClassTemplateDefinition(className, _context.Header, _context.Class);
                        break;
                    case CursorKind.EnumDecl:
                        @class = new EnumDefinition(className, _context.Header, _context.Class);
                        break;
                    default:
                        @class = new ClassDefinition(className, _context.Header, _context.Class);
                        break;
                }

                @class.NamespaceName = _context.Namespace;

                if (@class.FullyQualifiedName != fullyQualifiedName)
                {
                    Console.WriteLine("Parsing error at " + fullyQualifiedName);
                }
                project.ClassDefinitions[fullyQualifiedName] = @class;
            }

            _context.Class = @class;
            _context.Class.IsParsed = true;

            // Unnamed struct escapes to the surrounding scope
            if (!(string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl))
            {
                if (_context.Class.Parent != null)
                {
                    _context.Class.Parent.NestedClasses.Add(_context.Class);
                }
                else
                {
                    _context.Header.Classes.Add(_context.Class);
                }
            }

            AccessSpecifier parentMemberAccess = _context.MemberAccess;

            // Default class/struct access specifier
            switch (cursor.Kind)
            {
                case CursorKind.ClassDecl:
                    _context.MemberAccess = AccessSpecifier.Private;
                    break;
                case CursorKind.StructDecl:
                    _context.Class.IsStruct = true;
                    _context.MemberAccess = AccessSpecifier.Public;
                    break;
                case CursorKind.ClassTemplate:
                    if (cursor.TemplateCursorKind != CursorKind.ClassDecl)
                    {
                        _context.MemberAccess = AccessSpecifier.Private;
                    }
                    else
                    {
                        _context.MemberAccess = AccessSpecifier.Public;
                    }
                    break;
                case CursorKind.TypedefDecl:
                    var underlying = cursor.TypedefDeclUnderlyingType.Canonical;
                    if (underlying.TypeKind == ClangSharp.Type.Kind.Pointer &&
                        underlying.Pointee.TypeKind == ClangSharp.Type.Kind.FunctionProto)
                    {
                        _context.Class.IsFunctionProto = true;
                    }
                    break;
            }

            if (cursor.Kind == CursorKind.EnumDecl)
            {
                var @enum = _context.Class as EnumDefinition;

                foreach (var constantDecl in cursor.Children
                    .Where(c => c.Kind == CursorKind.EnumConstantDecl))
                {
                    string valueSpelling = "";
                    var value = constantDecl.Children.FirstOrDefault();
                    if (value != null)
                    {
                        var valueTokens = _context.TranslationUnit.Tokenize(value.Extent)
                            .Where(t => t.Kind != TokenKind.Comment &&
                                !t.Spelling.Equals(",") &&
                                !t.Spelling.Equals("}"));
                        valueSpelling = string.Join("", valueTokens.Select(t => t.Spelling));
                    }
                    @enum.EnumConstants.Add(new EnumConstant(constantDecl.Spelling, valueSpelling));
                }
            }
            else
            {
                cursor.VisitChildren(ClassVisitor);

                if (_context.Class.BaseClass == null)
                {
                    // Clang doesn't give the base class if it's a template,
                    // tokenize the class definition and extract the base template if it exists
                    ParseTemplateBaseCursor(cursor);
                }
            }

            // Restore parent state
            _context.Class = _context.Class.Parent;
            _context.MemberAccess = parentMemberAccess;
        }
        void WriteEnumClass(EnumDefinition e, int level)
        {
            EnsureWhiteSpace(WriteTo.CS);

            if (e.Name.EndsWith("Flags"))
            {
                WriteTabs(level, WriteTo.CS);
                WriteLine("[Flags]", WriteTo.CS);
            }

            WriteTabs(level, WriteTo.CS);
            WriteLine(string.Format("public enum {0}", e.Name), WriteTo.CS);
            WriteTabs(level, WriteTo.CS);
            WriteLine('{', WriteTo.CS);
            for (int i = 0; i < e.EnumConstants.Count; i++)
            {
                WriteTabs(level + 1, WriteTo.CS);
                Write(e.EnumConstants[i], WriteTo.CS);
                Write(" = ", WriteTo.CS);
                Write(e.EnumConstantValues[i], WriteTo.CS);
                if (i < e.EnumConstants.Count - 1)
                {
                    Write(',', WriteTo.CS);
                }
                WriteLine(WriteTo.CS);
            }
            WriteTabs(level, WriteTo.CS);
            WriteLine('}', WriteTo.CS);
            hasCSWhiteSpace = false;
            hasClassSeparatingWhitespace = false;
        }
        void ParseClassCursor(Cursor cursor)
        {
            string className = cursor.Spelling;
            string fullyQualifiedName;

            if (cursor.Type.TypeKind != ClangSharp.Type.Kind.Invalid)
            {
                fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor.Type);
            }
            else if (currentClass != null)
            {
                fullyQualifiedName = currentClass.FullName + "::" + className;
            }
            else
            {
                fullyQualifiedName = className;
            }

            if (ClassDefinitions.ContainsKey(fullyQualifiedName))
            {
                return;
            }

            if (string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl && currentClass == null)
            {
                return;
            }

            if (currentClass != null)
            {
                currentClass = new ClassDefinition(className, currentClass);
            }
            else
            {
                currentClass = new ClassDefinition(className, currentHeader);
            }

            // Unnamed struct escapes to the surrounding scope
            if (!(string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl))
            {
                ClassDefinitions.Add(fullyQualifiedName, currentClass);

                if (currentClass.Parent != null)
                {
                    currentClass.Parent.Classes.Add(currentClass);
                }
                else
                {
                    currentHeader.Classes.Add(currentClass);
                }
            }

            AccessSpecifier parentMemberAccess = currentMemberAccess;

            // Default class/struct access specifier
            if (cursor.Kind == CursorKind.ClassDecl)
            {
                currentMemberAccess = AccessSpecifier.Private;
            }
            else if (cursor.Kind == CursorKind.StructDecl)
            {
                currentClass.IsStruct = true;
                currentMemberAccess = AccessSpecifier.Public;
            }
            else if (cursor.Kind == CursorKind.ClassTemplate)
            {
                currentClass.IsTemplate = true;
                if (cursor.TemplateCursorKind != CursorKind.ClassDecl)
                {
                    currentMemberAccess = AccessSpecifier.Private;
                }
                else
                {
                    currentMemberAccess = AccessSpecifier.Public;
                }
            }

            if (cursor.Kind == CursorKind.EnumDecl)
            {
                currentEnum = new EnumDefinition(fullyQualifiedName, cursor.Spelling);
                currentHeader.Enums.Add(currentEnum);
                cursor.VisitChildren(EnumVisitor);
                if (currentClass != null)
                {
                    // Enum wrapped in a struct
                    currentClass.Enum = currentEnum;
                }
                currentEnum = null;
            }
            else if (cursor.Kind == CursorKind.TypedefDecl)
            {
                currentClass.IsTypedef = true;
                if (cursor.TypedefDeclUnderlyingType.Canonical.TypeKind != ClangSharp.Type.Kind.FunctionProto)
                {
                    currentClass.TypedefUnderlyingType = new TypeRefDefinition(cursor.TypedefDeclUnderlyingType);
                }
            }
            else
            {
                cursor.VisitChildren(ClassVisitor);
            }

            // Restore parent state
            currentClass = currentClass.Parent;
            currentMemberAccess = parentMemberAccess;
        }
Example #4
0
        void ParseClassCursor(Cursor cursor)
        {
            string className          = cursor.Spelling;
            string fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor);

            ClassDefinition @class;

            if (project.ClassDefinitions.TryGetValue(fullyQualifiedName, out @class))
            {
                if (@class.IsParsed)
                {
                    return;
                }

                @class.Parent = _context.Class;
            }
            else
            {
                switch (cursor.Kind)
                {
                case CursorKind.ClassTemplate:
                    @class = new ClassTemplateDefinition(className, _context.Header, _context.Class);
                    break;

                case CursorKind.EnumDecl:
                    @class = new EnumDefinition(className, _context.Header, _context.Class);
                    break;

                default:
                    @class = new ClassDefinition(className, _context.Header, _context.Class);
                    break;
                }

                @class.NamespaceName = _context.Namespace;

                if (@class.FullyQualifiedName != fullyQualifiedName)
                {
                    Console.WriteLine("Parsing error at " + fullyQualifiedName);
                }
                project.ClassDefinitions[fullyQualifiedName] = @class;
            }

            _context.Class          = @class;
            _context.Class.IsParsed = true;

            // Unnamed struct escapes to the surrounding scope
            if (!(string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl))
            {
                if (_context.Class.Parent != null)
                {
                    _context.Class.Parent.NestedClasses.Add(_context.Class);
                }
                else
                {
                    _context.Header.Classes.Add(_context.Class);
                }
            }

            AccessSpecifier parentMemberAccess = _context.MemberAccess;

            // Default class/struct access specifier
            switch (cursor.Kind)
            {
            case CursorKind.ClassDecl:
                _context.MemberAccess = AccessSpecifier.Private;
                break;

            case CursorKind.StructDecl:
                _context.Class.IsStruct = true;
                _context.MemberAccess   = AccessSpecifier.Public;
                break;

            case CursorKind.ClassTemplate:
                if (cursor.TemplateCursorKind != CursorKind.ClassDecl)
                {
                    _context.MemberAccess = AccessSpecifier.Private;
                }
                else
                {
                    _context.MemberAccess = AccessSpecifier.Public;
                }
                break;

            case CursorKind.TypedefDecl:
                var underlying = cursor.TypedefDeclUnderlyingType.Canonical;
                if (underlying.TypeKind == ClangSharp.Type.Kind.Pointer &&
                    underlying.Pointee.TypeKind == ClangSharp.Type.Kind.FunctionProto)
                {
                    _context.Class.IsFunctionProto = true;
                }
                break;
            }

            if (cursor.Kind == CursorKind.EnumDecl)
            {
                var @enum = _context.Class as EnumDefinition;

                foreach (var constantDecl in cursor.Children
                         .Where(c => c.Kind == CursorKind.EnumConstantDecl))
                {
                    string valueSpelling = "";
                    var    value         = constantDecl.Children.FirstOrDefault();
                    if (value != null)
                    {
                        var valueTokens = _context.TranslationUnit.Tokenize(value.Extent)
                                          .Where(t => t.Kind != TokenKind.Comment &&
                                                 !t.Spelling.Equals(",") &&
                                                 !t.Spelling.Equals("}"));
                        valueSpelling = string.Join("", valueTokens.Select(t => t.Spelling));
                    }
                    @enum.EnumConstants.Add(new EnumConstant(constantDecl.Spelling, valueSpelling));
                }
            }
            else
            {
                cursor.VisitChildren(ClassVisitor);

                if (_context.Class.BaseClass == null)
                {
                    // Clang doesn't give the base class if it's a template,
                    // tokenize the class definition and extract the base template if it exists
                    var tokens = _context.TranslationUnit.Tokenize(cursor.Extent)
                                 .TakeWhile(t => !t.Spelling.Equals("{"))
                                 .SkipWhile(t => !t.Spelling.Equals(":"));
                    if (tokens.Any())
                    {
                        var baseTokens = tokens.ToList();
                        int templSpecStart = -1, templSpecEnd = -1;
                        for (int i = 0; i < baseTokens.Count; i++)
                        {
                            var token = baseTokens[i];
                            if (token.Spelling == "<")
                            {
                                templSpecStart = i;
                            }
                            else if (token.Spelling == ">")
                            {
                                templSpecEnd = i;
                            }
                        }
                        if (templSpecStart != -1 && templSpecEnd != -1)
                        {
                            string template     = baseTokens[templSpecStart - 1].Spelling;
                            string templateSpec = string.Join(" ",
                                                              baseTokens.GetRange(templSpecStart + 1, templSpecEnd - templSpecStart - 1)
                                                              .Select(t => t.Spelling));

                            string          templateName = $"{template}<{templateSpec}>";
                            ClassDefinition classTemplate;
                            if (!project.ClassDefinitions.TryGetValue(templateName, out classTemplate))
                            {
                                var classTemplateNew = new ClassTemplateDefinition(template, _context.Header);
                                classTemplateNew.TemplateParameters.Add(templateSpec);

                                var baseTemplate = project.ClassDefinitions.FirstOrDefault(c => c.Value.Name.Equals(template));
                                classTemplateNew.BaseClass = baseTemplate.Value;

                                project.ClassDefinitions[templateName] = classTemplateNew;
                                classTemplate = classTemplateNew;
                            }

                            _context.Class.BaseClass = classTemplate;
                        }
                    }
                }
            }

            // Restore parent state
            _context.Class        = _context.Class.Parent;
            _context.MemberAccess = parentMemberAccess;
        }
        Cursor.ChildVisitResult HeaderVisitor(Cursor cursor, Cursor parent)
        {
            string filename = cursor.Extent.Start.File.Name.Replace('\\', '/');
            if (!filename.StartsWith(src, StringComparison.OrdinalIgnoreCase))
            {
                return Cursor.ChildVisitResult.Continue;
            }

            // Have we visited this header already?
            if (HeaderDefinitions.ContainsKey(filename))
            {
                currentHeader = HeaderDefinitions[filename];
            }
            else
            {
                // No, define a new one
                string relativeFilename = filename.Substring(src.Length);
                currentHeader = new HeaderDefinition(relativeFilename);
                HeaderDefinitions.Add(filename, currentHeader);
                headerQueue.Remove(filename);
            }

            if ((cursor.Kind == CursorKind.ClassDecl || cursor.Kind == CursorKind.StructDecl ||
                cursor.Kind == CursorKind.ClassTemplate || cursor.Kind == CursorKind.TypedefDecl) && cursor.IsDefinition)
            {
                ParseClassCursor(cursor);
            }
            else if (cursor.Kind == CursorKind.EnumDecl)
            {
                if (!currentHeader.Enums.Any(x => x.Name.Equals(cursor.Spelling)))
                {
                    currentEnum = new EnumDefinition(cursor.Spelling, cursor.Spelling);
                    currentHeader.Enums.Add(currentEnum);
                    cursor.VisitChildren(EnumVisitor);
                    currentEnum = null;
                }
            }
            else if (cursor.Kind == CursorKind.Namespace)
            {
                return Cursor.ChildVisitResult.Recurse;
            }
            return Cursor.ChildVisitResult.Continue;
        }