Cursor.ChildVisitResult ClassVisitor(Cursor cursor, Cursor parent) { if (cursor.Kind == CursorKind.CxxAccessSpecifier) { currentMemberAccess = cursor.AccessSpecifier; return Cursor.ChildVisitResult.Continue; } else if (cursor.Kind == CursorKind.CxxBaseSpecifier) { currentClass.BaseClass = new TypeRefDefinition(cursor.Type); return Cursor.ChildVisitResult.Continue; } if (currentMemberAccess != AccessSpecifier.Public) { 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.ContainsKey(methodName)) { return Cursor.ChildVisitResult.Continue; } currentMethod = new MethodDefinition(methodName, currentClass, cursor.NumArguments); currentMethod.ReturnType = new TypeRefDefinition(cursor.ResultType); currentMethod.IsStatic = cursor.IsStaticCxxMethod; currentMethod.IsConstructor = cursor.Kind == CursorKind.Constructor; if (cursor.IsVirtualCxxMethod) { currentMethod.IsVirtual = true; if (cursor.IsPureVirtualCxxMethod) { currentMethod.IsAbstract = true; currentClass.IsAbstract = true; } } // 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; } currentParameter = new ParameterDefinition(parameterName, new TypeRefDefinition(arg.Type)); currentMethod.Parameters[i] = currentParameter; arg.VisitChildren(MethodTemplateTypeVisitor); currentParameter = null; // Check if it's a const or optional parameter IEnumerable<Token> argTokens = currentTU.Tokenize(arg.Extent); foreach (Token token in argTokens) { if (token.Spelling.Equals("=")) { currentMethod.Parameters[i].IsOptional = true; } } } currentMethod = null; } else if (cursor.Kind == CursorKind.FieldDecl) { currentField = new FieldDefinition(cursor.Spelling, new TypeRefDefinition(cursor.Type), currentClass); currentFieldHasSpecializedParameter = false; cursor.VisitChildren(FieldTemplateTypeVisitor); currentField = null; } else if (cursor.Kind == CursorKind.UnionDecl) { return Cursor.ChildVisitResult.Recurse; } else { //Console.WriteLine(cursor.Spelling); } return Cursor.ChildVisitResult.Continue; }
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; }
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; } 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); _context.Method.IsConstructor = cursor.Kind == CursorKind.Constructor; _context.Method.IsStatic = cursor.IsStaticCxxMethod; _context.Method.IsVirtual = cursor.IsVirtualCxxMethod; _context.Method.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; } if (_context.Method.Parameters[i] == null) { _context.Parameter = new ParameterDefinition(parameterName, new TypeRefDefinition(arg.Type)); _context.Method.Parameters[i] = _context.Parameter; } else { _context.Parameter = _context.Method.Parameters[i]; _context.Parameter.Type = new TypeRefDefinition(arg.Type); } 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.IsParsed = true; _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; }