diff --git a/src/Generator/AST/ASTRecord.cs b/src/Generator/AST/ASTRecord.cs new file mode 100644 index 00000000..68155ea9 --- /dev/null +++ b/src/Generator/AST/ASTRecord.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using CppSharp.AST; +using Type = CppSharp.AST.Type; + +namespace CppSharp.Generators.AST +{ + public class ASTRecord + { + public ASTRecord Parent; + public object Object; + + public bool GetParent(out T @out) + { + @out = default(T); + + if (Parent == null) + return false; + + var v = Parent.Object; + if (!(v is T)) + return false; + + @out = (T) v; + return true; + } + + // Pushes ancestors into the stack until it is found one of type T. + public bool GetAncestors(ref Stack ancestors) + { + ancestors.Push(this); + + T value; + if (GetParent(out value)) + { + ancestors.Push(value); + return true; + } + + return Parent != null + && Parent.GetAncestors(ref ancestors); + } + } + + public class ASTRecord : ASTRecord + { + public T Value + { + get { return (T) Object; } + } + } + + public class ASTRecordStack + { + private readonly Stack recordStack; + + public ASTRecordStack() + { + recordStack = new Stack(); + } + + public ASTRecord Push(T value) + { + ASTRecord parent = null; + + if (recordStack.Count > 0) + parent = recordStack.Peek(); + + var record = new ASTRecord() + { + Parent = parent, + Object = value + }; + recordStack.Push(record); + return record; + } + + public void Pop() + { + recordStack.Pop(); + } + } + + static class ASTRecordExtensions + { + public static bool IsBaseClass(this ASTRecord record) + { + Class decl; + return record.GetParent(out decl) && decl.BaseClass == record.Object; + } + + public static bool IsFieldValueType(this ASTRecord record) + { + var ancestors = new Stack(); + if(!record.GetAncestors(ref ancestors)) + return false; + + var field = (Field)ancestors.Pop(); + + Class decl; + if (!field.Type.Desugar().IsTagDecl(out decl)) + return false; + + return decl.IsValueType; + } + } + + public class RecordCollector : AstVisitor + { + public readonly ISet> Declarations; + private readonly ASTRecordStack recordStack; + + public TranslationUnit translationUnit; + + public ISet Visited2 { get; private set; } + public bool AlreadyVisited2(object o) + { + return !Visited2.Add(o); + } + + public RecordCollector(TranslationUnit translationUnit) + { + this.translationUnit = translationUnit; + Declarations = new HashSet>(); + recordStack = new ASTRecordStack(); + Visited2 = new HashSet(); + } + + public override bool VisitDeclaration(Declaration decl) + { + if(translationUnit.FileName.Contains("Font")) + Console.Write(""); + + if (decl.IsIncomplete && decl.CompleteDeclaration != null) + decl = decl.CompleteDeclaration; + + if(AlreadyVisited2(decl)) + return ShouldVisitChilds(decl); + Visited.Remove(decl); // So Class can be revisited + + Declarations.Add(recordStack.Push(decl)); + decl.Visit(this); + recordStack.Pop(); + + return false; + } + + public override bool VisitType(Type type, TypeQualifiers quals) + { + type = type.Desugar(); + + if(AlreadyVisited2(type)) + return true; + + recordStack.Push(type); + type.Visit(this); + recordStack.Pop(); + + return false; + } + + public bool ShouldVisitChilds(Declaration decl) + { + if(decl == translationUnit) + return true; + + if (decl is TranslationUnit) + return false; + + if (decl.Namespace == null) + return true; + + // No need to continue visiting after a declaration of + // another translation unit is encountered. + return decl.Namespace.TranslationUnit == translationUnit; + } + } +}