diff --git a/sources/ClangSharp/Cursors/Cursor.cs b/sources/ClangSharp/Cursors/Cursor.cs index 528efd5e..8fd4b949 100644 --- a/sources/ClangSharp/Cursors/Cursor.cs +++ b/sources/ClangSharp/Cursors/Cursor.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using ClangSharp.Interop; namespace ClangSharp @@ -10,10 +12,12 @@ namespace ClangSharp [DebuggerDisplay("{Handle.DebuggerDisplayString,nq}")] public unsafe class Cursor : IEquatable { - private readonly Lazy> _cursorChildren; + private readonly Lazy _kindSpelling; private readonly Lazy _lexicalParentCursor; private readonly Lazy _semanticParentCursor; + private readonly Lazy _spelling; private readonly Lazy _translationUnit; + private List _cursorChildren; private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind) { @@ -23,28 +27,60 @@ private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind) } Handle = handle; - _cursorChildren = new Lazy>(() => { - var cursors = new List(); - - _ = Handle.VisitChildren((cursor, parent, clientData) => { - var cursorChild = TranslationUnit.GetOrCreate(cursor); - cursors.Add(cursorChild); - return CXChildVisitResult.CXChildVisit_Continue; - }, clientData: default); - - return cursors; - }); - + _kindSpelling = new Lazy(() => Handle.KindSpelling.ToString()); _lexicalParentCursor = new Lazy(() => TranslationUnit.GetOrCreate(Handle.LexicalParent)); _semanticParentCursor = new Lazy(() => TranslationUnit.GetOrCreate(Handle.SemanticParent)); + _spelling = new Lazy(() => Handle.Spelling.ToString()); _translationUnit = new Lazy(() => TranslationUnit.GetOrCreate(Handle.TranslationUnit)); } - public IReadOnlyList CursorChildren => _cursorChildren.Value; + public IReadOnlyList CursorChildren + { + get + { + if (_cursorChildren is null) + { + var cursorChildren = GCHandle.Alloc(new List()); + +#if !NET5_0_OR_GREATER + var visitor = (CXCursorVisitor)Visitor; + var pVisitor = Marshal.GetFunctionPointerForDelegate(visitor); +#else + var pVisitor = (delegate* unmanaged[Cdecl])&Visitor; +#endif + + var client_data = stackalloc nint[2] { + GCHandle.ToIntPtr(cursorChildren), + TranslationUnit.Handle.Handle + }; + + _ = clang.visitChildren(Handle, (IntPtr)pVisitor, client_data); + + _cursorChildren = (List)cursorChildren.Target; + cursorChildren.Free(); + +#if !NET5_0_OR_GREATER + GC.KeepAlive(visitor); +#else + [UnmanagedCallersOnly(CallConvs = new System.Type[] { typeof(CallConvCdecl) })] +#endif + static CXChildVisitResult Visitor(CXCursor cursor, CXCursor parent, void* client_data) + { + var cursorChildren = (List)GCHandle.FromIntPtr(((nint*)client_data)[0]).Target; + var translationUnit = TranslationUnit.GetOrCreate((CXTranslationUnitImpl*)((nint*)client_data)[1]); + + var cursorChild = translationUnit.GetOrCreate(cursor); + cursorChildren.Add(cursorChild); + return CXChildVisitResult.CXChildVisit_Continue; + } + } + return _cursorChildren; + } + } - public CXCursorKind CursorKind => Handle.Kind; + public CXCursorKind CursorKind => Handle.kind; - public string CursorKindSpelling => Handle.KindSpelling.ToString(); + public string CursorKindSpelling => _kindSpelling.Value; public CXSourceRange Extent => Handle.Extent; @@ -56,7 +92,7 @@ private protected Cursor(CXCursor handle, CXCursorKind expectedCursorKind) public Cursor SemanticParentCursor => _semanticParentCursor.Value; - public string Spelling => Handle.Spelling.ToString(); + public string Spelling => _spelling.Value; public TranslationUnit TranslationUnit => _translationUnit.Value; @@ -103,6 +139,6 @@ internal static Cursor Create(CXCursor handle) public override int GetHashCode() => Handle.GetHashCode(); - public override string ToString() => Handle.ToString(); + public override string ToString() => Spelling; } } diff --git a/sources/ClangSharp/Types/Type.cs b/sources/ClangSharp/Types/Type.cs index 8fe315df..0a917a00 100644 --- a/sources/ClangSharp/Types/Type.cs +++ b/sources/ClangSharp/Types/Type.cs @@ -9,8 +9,10 @@ namespace ClangSharp [DebuggerDisplay("{Handle.DebuggerDisplayString,nq}")] public unsafe class Type : IEquatable { + private readonly Lazy _asString; private readonly Lazy _canonicalType; private readonly Lazy _desugar; + private readonly Lazy _kindSpelling; private readonly Lazy _pointeeType; private readonly Lazy _translationUnit; @@ -27,15 +29,17 @@ protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedType } Handle = handle; + _asString = new Lazy(() => Handle.Spelling.ToString()); _canonicalType = new Lazy(() => TranslationUnit.GetOrCreate(Handle.CanonicalType)); _desugar = new Lazy(() => TranslationUnit.GetOrCreate(Handle.Desugar)); + _kindSpelling = new Lazy(() => Handle.KindSpelling.ToString()); _pointeeType = new Lazy(() => TranslationUnit.GetOrCreate(Handle.PointeeType)); _translationUnit = new Lazy(() => TranslationUnit.GetOrCreate((CXTranslationUnit)Handle.data[1])); } public CXXRecordDecl AsCXXRecordDecl => AsTagDecl as CXXRecordDecl; - public string AsString => Handle.Spelling.ToString(); + public string AsString => _asString.Value; public TagDecl AsTagDecl { @@ -79,7 +83,7 @@ public bool IsIntegralOrEnumerationType public CXTypeKind Kind => Handle.kind; - public string KindSpelling => Handle.KindSpelling.ToString(); + public string KindSpelling => _kindSpelling.Value; public Type PointeeType => _pointeeType.Value; @@ -191,6 +195,6 @@ public T GetAs() public override int GetHashCode() => Handle.GetHashCode(); - public override string ToString() => Handle.ToString(); + public override string ToString() => AsString; } }