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; }
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; }