Esempio n. 1
0
        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;
        }
        Cursor.ChildVisitResult ClassVisitor(Cursor cursor, Cursor parent)
        {
            switch (cursor.Kind)
            {
            case CursorKind.CxxAccessSpecifier:
                _context.MemberAccess = cursor.AccessSpecifier;
                return(Cursor.ChildVisitResult.Continue);

            case CursorKind.CxxBaseSpecifier:
                string          baseName = TypeRefDefinition.GetFullyQualifiedName(cursor.Type);
                ClassDefinition baseClass;
                if (!project.ClassDefinitions.TryGetValue(baseName, out baseClass))
                {
                    Console.WriteLine("Base {0} for {1} not found! Missing header?", baseName, _context.Class.Name);
                    return(Cursor.ChildVisitResult.Continue);
                }
                _context.Class.BaseClass = baseClass;
                return(Cursor.ChildVisitResult.Continue);

            case CursorKind.TemplateTypeParameter:
                var classTemplate = _context.Class as ClassTemplateDefinition;
                if (classTemplate.TemplateTypeParameters == null)
                {
                    classTemplate.TemplateTypeParameters = new List <string>();
                }
                classTemplate.TemplateTypeParameters.Add(cursor.Spelling);
                return(Cursor.ChildVisitResult.Continue);
            }

            // We only care about public members
            if (_context.MemberAccess != AccessSpecifier.Public)
            {
                // And also private/protected virtual methods that override public abstract methods,
                // necessary for checking whether a class is abstract or not.
                if (cursor.IsPureVirtualCxxMethod || !cursor.IsVirtualCxxMethod)
                {
                    return(Cursor.ChildVisitResult.Continue);
                }
            }

            if ((cursor.Kind == CursorKind.ClassDecl || cursor.Kind == CursorKind.StructDecl ||
                 cursor.Kind == CursorKind.ClassTemplate || cursor.Kind == CursorKind.TypedefDecl ||
                 cursor.Kind == CursorKind.EnumDecl) && cursor.IsDefinition)
            {
                ParseClassCursor(cursor);
            }
            else if (cursor.Kind == CursorKind.CxxMethod || cursor.Kind == CursorKind.Constructor)
            {
                string methodName = cursor.Spelling;
                if (excludedMethods.Contains(methodName))
                {
                    return(Cursor.ChildVisitResult.Continue);
                }

                _context.Method = new MethodDefinition(methodName, _context.Class, cursor.NumArguments)
                {
                    ReturnType    = new TypeRefDefinition(cursor.ResultType),
                    IsConstructor = cursor.Kind == CursorKind.Constructor,
                    IsStatic      = cursor.IsStaticCxxMethod,
                    IsVirtual     = cursor.IsVirtualCxxMethod,
                    IsAbstract    = cursor.IsPureVirtualCxxMethod
                };

                // Check if the return type is a template
                cursor.VisitChildren(MethodTemplateTypeVisitor);

                // Parse arguments
                for (uint i = 0; i < cursor.NumArguments; i++)
                {
                    Cursor arg = cursor.GetArgument(i);

                    string parameterName = arg.Spelling;
                    if (parameterName.Length == 0)
                    {
                        parameterName = "__unnamed" + i;
                    }

                    _context.Parameter            = new ParameterDefinition(parameterName, new TypeRefDefinition(arg.Type));
                    _context.Method.Parameters[i] = _context.Parameter;
                    arg.VisitChildren(MethodTemplateTypeVisitor);

                    // Check for a default value (optional parameter)
                    var argTokens = _context.TranslationUnit.Tokenize(arg.Extent);
                    if (argTokens.Any(a => a.Spelling.Equals("=")))
                    {
                        _context.Parameter.IsOptional = true;
                    }

                    // Get marshalling direction
                    if (_context.Parameter.Type.IsPointer || _context.Parameter.Type.IsReference)
                    {
                        if (_context.Parameter.MarshalDirection != MarshalDirection.Out &&
                            !_context.TranslationUnit.Tokenize(arg.Extent).Any(a => a.Spelling.Equals("const")))
                        {
                            _context.Parameter.MarshalDirection = MarshalDirection.InOut;
                        }
                    }

                    _context.Parameter = null;
                }

                // Discard any private/protected virtual method unless it
                // implements a public abstract method
                if (_context.MemberAccess != AccessSpecifier.Public)
                {
                    if (_context.Method.Parent.BaseClass == null ||
                        !_context.Method.Parent.BaseClass.AbstractMethods.Contains(_context.Method))
                    {
                        _context.Method.Parent.Methods.Remove(_context.Method);
                    }
                }

                _context.Method = null;
            }
            else if (cursor.Kind == CursorKind.FieldDecl)
            {
                _context.Field = new FieldDefinition(cursor.Spelling,
                                                     new TypeRefDefinition(cursor.Type), _context.Class);
                if (!cursor.Type.Declaration.SpecializedCursorTemplate.IsInvalid)
                {
                    if (cursor.Children[0].Kind != CursorKind.TemplateRef)
                    {
                        throw new InvalidOperationException();
                    }
                    if (cursor.Children.Count == 1)
                    {
                        string displayName = cursor.Type.Declaration.DisplayName;
                        int    typeStart   = displayName.IndexOf('<') + 1;
                        int    typeEnd     = displayName.LastIndexOf('>');
                        displayName = displayName.Substring(typeStart, typeEnd - typeStart);
                        var specializationTypeRef = new TypeRefDefinition
                        {
                            IsBasic = true,
                            Name    = displayName
                        };
                        _context.Field.Type.SpecializedTemplateType = specializationTypeRef;
                    }
                    if (cursor.Children.Count == 2)
                    {
                        if (cursor.Children[1].Type.TypeKind != ClangSharp.Type.Kind.Invalid)
                        {
                            _context.Field.Type.SpecializedTemplateType = new TypeRefDefinition(cursor.Children[1].Type);
                        }
                        else
                        {
                            // TODO
                        }
                    }
                }
                //cursor.VisitChildren(FieldTemplateTypeVisitor);
                _context.Field = null;
            }
            else if (cursor.Kind == CursorKind.UnionDecl)
            {
                return(Cursor.ChildVisitResult.Recurse);
            }
            else
            {
                //Console.WriteLine(cursor.Spelling);
            }
            return(Cursor.ChildVisitResult.Continue);
        }
Esempio n. 3
0
        Cursor.ChildVisitResult ClassVisitor(Cursor cursor, Cursor parent)
        {
            switch (cursor.Kind)
            {
            case CursorKind.CxxAccessSpecifier:
                _context.MemberAccess = cursor.AccessSpecifier;
                return(Cursor.ChildVisitResult.Continue);

            case CursorKind.CxxBaseSpecifier:
                string          baseName = TypeRefDefinition.GetFullyQualifiedName(cursor.Type.Declaration);
                ClassDefinition baseClass;
                if (!project.ClassDefinitions.TryGetValue(baseName, out baseClass))
                {
                    Console.WriteLine("Base {0} for {1} not found! Missing header?", baseName, _context.Class.Name);
                    return(Cursor.ChildVisitResult.Continue);
                }
                _context.Class.BaseClass = baseClass;
                return(Cursor.ChildVisitResult.Continue);

            case CursorKind.TemplateTypeParameter:
                var classTemplate = _context.Class as ClassTemplateDefinition;
                if (!classTemplate.TemplateParameters.Contains(cursor.Spelling))
                {
                    classTemplate.TemplateParameters.Add(cursor.Spelling);
                }
                return(Cursor.ChildVisitResult.Continue);
            }

            // We usually only care about public members
            if (_context.MemberAccess != AccessSpecifier.Public)
            {
                if (cursor.IsVirtualCxxMethod && !cursor.IsPureVirtualCxxMethod)
                {
                    // private/protected virtual method that may override public abstract methods,
                    // necessary for checking whether a class is abstract or not.
                }
                else if (cursor.Kind == CursorKind.Constructor)
                {
                    // class has a private/protected constructor,
                    // no need to create a default constructor
                }
                else
                {
                    return(Cursor.ChildVisitResult.Continue);
                }
            }

            switch (cursor.Kind)
            {
            case CursorKind.ClassDecl:
            case CursorKind.StructDecl:
            case CursorKind.ClassTemplate:
            case CursorKind.EnumDecl:
                if (cursor.IsDefinition)
                {
                    ParseClassCursor(cursor);
                }
                break;


            case CursorKind.CxxMethod:
            case CursorKind.Constructor:
                ParseMethodCursor(cursor);
                break;

            case CursorKind.ConversionFunction:
            case CursorKind.FunctionTemplate:
            case CursorKind.Destructor:
                break;

            case CursorKind.FieldDecl:
                var field = new FieldDefinition(cursor.Spelling,
                                                new TypeRefDefinition(cursor.Type, cursor), _context.Class);
                break;

            case CursorKind.TypedefDecl:
                ParseTypedefCursor(cursor);
                break;

            case CursorKind.UnionDecl:
                return(Cursor.ChildVisitResult.Recurse);

            default:
                //Console.WriteLine(cursor.Spelling);
                break;
            }

            return(Cursor.ChildVisitResult.Continue);
        }
        void ParseClassCursor(Cursor cursor)
        {
            string className = cursor.Spelling;

            // Unnamed struct
            // A combined "typedef struct {}" definition is split into separate struct and typedef statements
            // where the struct is also a child of the typedef, so the struct can be skipped for now.
            if (string.IsNullOrEmpty(className) && cursor.Kind == CursorKind.StructDecl)
            {
                return;
            }

            string fullyQualifiedName = TypeRefDefinition.GetFullyQualifiedName(cursor);

            if (project.ClassDefinitions.ContainsKey(fullyQualifiedName))
            {
                if (project.ClassDefinitions[fullyQualifiedName].IsParsed)
                {
                    return;
                }
                var parent = _context.Class;
                _context.Class        = project.ClassDefinitions[fullyQualifiedName];
                _context.Class.Parent = parent;
            }
            else
            {
                if (cursor.Kind == CursorKind.ClassTemplate)
                {
                    _context.Class = new ClassTemplateDefinition(className, _context.Header, _context.Class);
                }
                else if (cursor.Kind == CursorKind.EnumDecl)
                {
                    _context.Class = new EnumDefinition(className, _context.Header, _context.Class);
                }
                else
                {
                    _context.Class = new ClassDefinition(className, _context.Header, _context.Class);
                }

                _context.Class.NamespaceName = _context.Namespace;

                if (_context.Class.FullyQualifiedName != fullyQualifiedName)
                {
                    // TODO
                }
                project.ClassDefinitions.Add(fullyQualifiedName, _context.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.Classes.Add(_context.Class);
                }
                else
                {
                    _context.Header.Classes.Add(_context.Class);
                }
            }

            AccessSpecifier parentMemberAccess = _context.MemberAccess;

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

            if (cursor.Kind == CursorKind.EnumDecl)
            {
                cursor.VisitChildren(EnumVisitor);
            }
            else if (cursor.Kind == CursorKind.TypedefDecl)
            {
                _context.Class.IsTypedef = true;
                if (cursor.TypedefDeclUnderlyingType.Canonical.TypeKind != ClangSharp.Type.Kind.FunctionProto)
                {
                    _context.Class.TypedefUnderlyingType = new TypeRefDefinition(cursor.TypedefDeclUnderlyingType);
                }
            }
            else
            {
                cursor.VisitChildren(ClassVisitor);
            }

            // Restore parent state
            _context.Class        = _context.Class.Parent;
            _context.MemberAccess = parentMemberAccess;
        }
Esempio n. 5
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
                    ParseTemplateBaseCursor(cursor);
                }
            }

            // Restore parent state
            _context.Class        = _context.Class.Parent;
            _context.MemberAccess = parentMemberAccess;
        }