Beispiel #1
0
        /// <summary>
        /// Analyse all function prototypes
        /// </summary>
        /// <param name="Cursor"></param>
        /// <returns></returns>
        public CElement CParser_VisitFunctionCursor(Cursor Cursor)
        {
            //first compute the md5 of the cursor and check if it already exist in database
            //if yes return the already created object
            string    md5 = CCodeFramework.Util.Util.ComputeMd5(Cursor);
            CFunction function;
            CElement  element = _DB.AstDB_FindElement(md5);

            if (element == null && Cursor.Kind != CursorKind.NoDeclFound)
            {
                function    = new CFunction();
                function.ID = md5;
                string fileName = Cursor.Location.File.Name.Replace('/', '\\');
                function.File          = fileName;
                function.Line          = Cursor.Location.Line;
                function.Column        = Cursor.Location.Column;
                function.ElementID     = CCodeFramework.Util.Util.ComputeElementMd5(Cursor);
                function.ElementKind   = ElementKind.Function;
                function.Name          = Cursor.Spelling;
                function.ProtoTypeHash = CCodeFramework.Util.Util.ComputeMd5(Cursor.ResultType);
                _DB.AstDB_AddElement(function);                                            //add the function object back to database
                CElement retur = _typeParser.CTypeParser_ParseDataType(Cursor.ResultType); //find the datatype of the return Type of the function
                function.ReturnType   = retur.ID;
                function.IsDefinition = Cursor.IsDefinition;

                function.StorageClass = (CCodeTypes.Types.StorageClass)Cursor.StorageClass;
                int argCount = Cursor.NumArguments;
                for (uint i = 0; i < argCount; i++)//iterate through all the arguments and find their name and type
                {
                    ClangSharp.Cursor cur = Cursor.GetArgument(i);
                    function.ProtoTypeHash += CCodeFramework.Util.Util.ComputeMd5(cur.Type);
                    function.Parameters.Add(CParser_VisitVariableCursor(cur));
                }
                var CalledFunctions = Cursor.Descendants.Where(x => x.Kind == CursorKind.CallExpr);//find all functions called from this function
                foreach (Cursor called in CalledFunctions)
                {
                    if (called.Referenced != null)                                                                                      //Referenced contain the original function cursor
                    {
                        if (called.Referenced.Location.File.Name != function.File && called.Referenced.Kind == CursorKind.FunctionDecl) //analyse only those functions which are not defined in the same file
                        {
                            function.Children.Add(CParser_VisitFunctionCursor(called.Referenced).ID);
                        }
                    }
                }
                return(function);
            }
            else
            {
                if (element is CFunction)//if already found in database check if that is of type Function
                {
                    function = element as CFunction;
                    return(function);
                }
                else
                {
                    return(null);
                }
            }
        }
        private void ParseTypedefCursor(Cursor cursor)
        {
            var underlying = cursor.TypedefDeclUnderlyingType.Canonical;

            // Does the typedef include a type declaration?
            if (cursor.Children.Any(c => c.Equals(underlying.Declaration)))
            {
                ParseClassCursor(underlying.Declaration);
                return;
            }

            // Function pointer
            if (underlying.TypeKind == ClangSharp.Type.Kind.Pointer &&
                underlying.Pointee.TypeKind == ClangSharp.Type.Kind.FunctionProto)
            {
                ParseClassCursor(cursor);
            }
        }
        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;
        }
        Cursor.ChildVisitResult HeaderVisitor(Cursor cursor, Cursor parent)
        {
            string filename = cursor.Extent.Start.File.Name.Replace('\\', '/');

            // Do not visit any included header
            if (!filename.Equals(_context.HeaderFilename)) return Cursor.ChildVisitResult.Continue;

            headerQueue.Remove(filename);

            // Have we visited this header already?
            HeaderDefinition header;
            if (!project.HeaderDefinitions.TryGetValue(filename, out header))
            {
                // No, define a new one
                header = new HeaderDefinition(filename);
                project.HeaderDefinitions[filename] = header;
            }
            _context.Header = header;

            if (cursor.IsDefinition)
            {
                switch (cursor.Kind)
                {
                    case CursorKind.ClassDecl:
                    case CursorKind.ClassTemplate:
                    case CursorKind.EnumDecl:
                    case CursorKind.StructDecl:
                        ParseClassCursor(cursor);
                        break;
                    case CursorKind.TypedefDecl:
                        ParseTypedefCursor(cursor);
                        break;
                    case CursorKind.Namespace:
                        _context.Namespace = cursor.Spelling;
                        cursor.VisitChildren(HeaderVisitor);
                        _context.Namespace = "";
                        break;
                }
            }

            return Cursor.ChildVisitResult.Continue;
        }
Beispiel #5
0
 public static extern uint clang_Cursor_isVariadic(Cursor native);
Beispiel #6
0
 public static extern int clang_Cursor_isNull(Cursor native);
Beispiel #7
0
 public static extern uint clang_Cursor_isBitField(Cursor native);
Beispiel #8
0
 public static extern uint clang_visitChildren(Cursor parent, CursorVisitor visitor, ClientData clientData);
Beispiel #9
0
 public static extern ClangString clang_getCursorDisplayName(Cursor c);
Beispiel #10
0
 public static extern ClangString clang_getCursorSpelling(Cursor c);
Beispiel #11
0
 public static extern ClangString clang_getCursorUSR(Cursor c);
Beispiel #12
0
 public static extern Type clang_getCursorResultType(Cursor c);
Beispiel #13
0
 internal static extern Type clang_getArgType(Cursor c, uint i);
Beispiel #14
0
 internal static extern Cursor clang_Cursor_getArgument(Cursor c, uint i);
Beispiel #15
0
 internal static extern int clang_Cursor_getNumArguments(Cursor c);
Beispiel #16
0
 internal static extern AccessSpecifier clang_getCXXAccessSpecifier(Cursor c);
Beispiel #17
0
 public static extern Cursor clang_getCursorReferenced(Cursor c);
Beispiel #18
0
 public static extern IntPtr clang_Cursor_getTranslationUnit(Cursor cursor); // TODO Does this need disposing?
Beispiel #19
0
 public static extern Cursor clang_getCursorDefinition(Cursor c);
Beispiel #20
0
 public static extern int clang_Cursor_isDynamicCall(Cursor native);
Beispiel #21
0
 public static extern uint clang_isCursorDefinition(Cursor c);
Beispiel #22
0
 public static extern uint clang_Cursor_isObjCOptional(Cursor native);
Beispiel #23
0
 public static extern uint clang_CXXMethod_isStatic(Cursor c);
Beispiel #24
0
 public static extern uint clang_isVirtualBase(Cursor c);
Beispiel #25
0
 internal static extern uint clang_CXXMethod_isVirtual(Cursor c);
        void ParseTemplateBaseCursor(Cursor cursor)
        {
            var tokens = _context.TranslationUnit.Tokenize(cursor.Extent)
                .TakeWhile(t => !t.Spelling.Equals("{"))
                .SkipWhile(t => !t.Spelling.Equals(":"));
            if (!tokens.Any()) return;

            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));
                templateSpec = TypeRefDefinition.GetBasicName(templateSpec);

                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;
                    _context.Header.Classes.Add(classTemplateNew);
                    classTemplate = classTemplateNew;
                }

                _context.Class.BaseClass = classTemplate;
            }
        }
Beispiel #27
0
 internal static extern CursorKind clang_getTemplateCursorKind(Cursor c);
        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;
        }
Beispiel #29
0
 internal static extern Cursor clang_getSpecializedCursorTemplate(Cursor c);
        private void ParseMethodCursor(Cursor cursor)
        {
            string methodName = cursor.Spelling;
            if (excludedMethods.Contains(methodName)) return;

            var existingMethodsMatch = _context.Class.Methods.Where(
                m => !m.IsParsed && methodName.Equals(m.Name) &&
                     m.Parameters.Length == cursor.NumArguments);
            int existingCount = existingMethodsMatch.Count();
            if (existingCount == 1)
            {
                // TODO: check method parameter types if given
                _context.Method = existingMethodsMatch.First();
            }
            else if (existingCount >= 2)
            {
                Console.WriteLine("Ambiguous method in project: " + methodName);
            }

            if (_context.Method == null)
            {
                _context.Method = new MethodDefinition(methodName, _context.Class, cursor.NumArguments);
            }

            _context.Method.ReturnType = new TypeRefDefinition(cursor.ResultType, cursor);
            _context.Method.IsStatic = cursor.IsStaticCxxMethod;
            _context.Method.IsVirtual = cursor.IsVirtualCxxMethod;
            _context.Method.IsAbstract = cursor.IsPureVirtualCxxMethod;
            _context.Method.Access = cursor.AccessSpecifier;
            _context.Method.IsConstructor = cursor.Kind == CursorKind.Constructor;

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

                if (_context.Method.Parameters[i] == null)
                {
                    _context.Parameter = new ParameterDefinition(arg.Spelling, new TypeRefDefinition(arg.Type, arg));
                    _context.Method.Parameters[i] = _context.Parameter;
                }
                else
                {
                    _context.Parameter = _context.Method.Parameters[i];
                    _context.Parameter.Type = new TypeRefDefinition(arg.Type);
                }

                // 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.MarshalDirection == MarshalDirection.Default)
                {
                    _context.Parameter.MarshalDirection = _context.Parameter.Type.GetDefaultMarshalDirection();
                }

                _context.Parameter = null;
            }

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

            _context.Method.IsParsed = true;
            _context.Method = null;
        }
Beispiel #31
0
 internal static extern SourceRange clang_getCursorReferenceNameRange(Cursor c);