diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 1635c12e..a7b70635 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1834,6 +1834,8 @@ public static void DisposeOverriddenCursors(ReadOnlySpan overridden) public readonly CXCursor GetDecl(uint index) => clangsharp.Cursor_getDecl(this, index); + public readonly bool GetDecls(CXCursor* cursors, uint count) => clangsharp.Cursor_getDecls(this, cursors, count); + public readonly void GetDefinitionSpellingAndExtent(out string spelling, out uint startLine, out uint startColumn, out uint endLine, out uint endColumn) { fixed (uint* pStartLine = &startLine) diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index bdba1616..bbb92795 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -6,7 +6,7 @@ namespace ClangSharp.Interop; -public static partial class @clangsharp +public static unsafe partial class @clangsharp { [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getArgument", ExactSpelling = true)] public static extern CXCursor Cursor_getArgument(CXCursor C, [NativeTypeName("unsigned int")] uint i); @@ -181,6 +181,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getDecl", ExactSpelling = true)] public static extern CXCursor Cursor_getDecl(CXCursor C, [NativeTypeName("unsigned int")] uint i); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getDecls", ExactSpelling = true)] + public static extern bool Cursor_getDecls(CXCursor C, CXCursor* decls, [NativeTypeName("unsigned int")] uint count); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getDeclKind", ExactSpelling = true)] public static extern CX_DeclKind Cursor_getDeclKind(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Decls/Decl.cs b/sources/ClangSharp/Cursors/Decls/Decl.cs index 28f54a59..13ff844d 100644 --- a/sources/ClangSharp/Cursors/Decls/Decl.cs +++ b/sources/ClangSharp/Cursors/Decls/Decl.cs @@ -35,7 +35,29 @@ private protected Decl(CXCursor handle, CXCursorKind expectedCursorKind, CX_Decl _attrs = LazyList.Create(Handle.NumAttrs, (i) => TranslationUnit.GetOrCreate(Handle.GetAttr(unchecked((uint)i)))); _body = new ValueLazy(() => !Handle.Body.IsNull ? TranslationUnit.GetOrCreate(Handle.Body) : null); _canonicalDecl = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.CanonicalCursor)); - _decls = LazyList.Create(Handle.NumDecls, (i) => TranslationUnit.GetOrCreate(Handle.GetDecl(unchecked((uint)i)))); + _decls = LazyList.Create(Handle.NumDecls, (i) => TranslationUnit.GetOrCreate(Handle.GetDecl(unchecked((uint)i))), (list) => { + var cursors = new CXCursor[list.Length]; + bool success; + unsafe { + fixed (CXCursor* first = cursors) { + success = Handle.GetDecls(first, unchecked((uint)list.Length)); + } + } + if (success) + { + for (var i = 0; i < list.Length; i++) + { + list[i] = TranslationUnit.GetOrCreate(cursors[i]); + } + } + else + { + for (var i = 0; i < list.Length; i++) + { + list[i] = TranslationUnit.GetOrCreate(Handle.GetDecl(unchecked((uint)i))); + } + } + }); _describedTemplate = new ValueLazy(() => { var describedTemplate = Handle.DescribedTemplate; return describedTemplate.IsNull ? null : TranslationUnit.GetOrCreate(describedTemplate); diff --git a/sources/ClangSharp/LazyList.cs b/sources/ClangSharp/LazyList.cs index 463005d0..b50c0906 100644 --- a/sources/ClangSharp/LazyList.cs +++ b/sources/ClangSharp/LazyList.cs @@ -7,14 +7,14 @@ namespace ClangSharp; internal static class LazyList { - public static LazyList Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>(int count, Func valueFactory) + public static LazyList Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>(int count, Func valueFactory, Action? allValuesFactory = null) where T : class { if (count <= 0) { return LazyList.Empty; } - return new LazyList(count, valueFactory); + return new LazyList(count, valueFactory, allValuesFactory); } public static LazyList Create(LazyList list, int skip = -1, int take = -1) diff --git a/sources/ClangSharp/LazyList`1.cs b/sources/ClangSharp/LazyList`1.cs index 507eeceb..7293e985 100644 --- a/sources/ClangSharp/LazyList`1.cs +++ b/sources/ClangSharp/LazyList`1.cs @@ -12,13 +12,15 @@ internal sealed class LazyList<[DynamicallyAccessedMembers(DynamicallyAccessedMe { internal readonly T[] _items; internal readonly Func _valueFactory; + internal readonly Action? _allValuesFactory; public static readonly LazyList Empty = new LazyList(0, _ => null!); - public LazyList(int count, Func valueFactory) + public LazyList(int count, Func valueFactory, Action? allValuesFactory = null) { _items = (count <= 0) ? [] : new T[count]; _valueFactory = valueFactory; + _allValuesFactory = allValuesFactory; } public T this[int index] @@ -30,8 +32,16 @@ public T this[int index] if (item is null) { - item = _valueFactory(index); - items[index] = item; + if (_allValuesFactory is not null) + { + _allValuesFactory(_items); + item = _items[index]; + } + else + { + item = _valueFactory(index); + items[index] = item; + } } return item; @@ -56,14 +66,7 @@ public void CopyTo(T[] array, int arrayIndex) for (var i = 0; i < items.Length; i++) { - var currentItem = items[i]; - - if (currentItem is null) - { - currentItem = _valueFactory(i); - items[i] = currentItem; - } - + var currentItem = this[i]; array[arrayIndex + i] = currentItem; } } @@ -76,14 +79,7 @@ public int IndexOf(T item) for (var i = 0; i < items.Length; i++) { - var currentItem = items[i]; - - if (currentItem is null) - { - currentItem = _valueFactory(i); - items[i] = currentItem; - } - + var currentItem = this[i]; if (EqualityComparer.Default.Equals(currentItem, item)) { return i; diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 93cadb0a..3edfefbf 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -943,6 +943,28 @@ CXType clangsharp_Cursor_getDeclaredReturnType(CXCursor C) { return MakeCXType(QualType(), getCursorTU(C)); } +bool clangsharp_Cursor_getDecls(CXCursor C, CXCursor* decls, unsigned count) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const DeclContext* DC = dyn_cast(D)) { + unsigned n = 0; + + for (auto decl : DC->decls()) { + if (n == count) { + return false; + } + decls[n] = MakeCXCursor(decl, getCursorTU(C)); + n++; + } + + return n == count; + } + } + + return false; +} + CXCursor clangsharp_Cursor_getDecl(CXCursor C, unsigned i) { if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index bbab9a61..f6922c85 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -341,6 +341,8 @@ CLANGSHARP_LINKAGE CXType clangsharp_Cursor_getDeclaredReturnType(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getDecl(CXCursor C, unsigned i); +CLANGSHARP_LINKAGE bool clangsharp_Cursor_getDecls(CXCursor C, CXCursor* decls, unsigned count); + CLANGSHARP_LINKAGE CX_DeclKind clangsharp_Cursor_getDeclKind(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getDecomposedDecl(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/CXCursor.cs b/tests/ClangSharp.UnitTests/CXCursor.cs index 1e4fcbed..3e379357 100644 --- a/tests/ClangSharp.UnitTests/CXCursor.cs +++ b/tests/ClangSharp.UnitTests/CXCursor.cs @@ -10,6 +10,7 @@ public class CXCursorTest : TranslationUnitTest [Test] public void AttrKindSpelling() { + AssertNeedNewClangSharp(); var inputContents = $$""" diff --git a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs index b3f6a0bb..46db9011 100644 --- a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs +++ b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs @@ -15,6 +15,8 @@ public sealed class DeclTest : TranslationUnitTest [TestCase("public", CX_CXXPublic)] public void AccessSpecDeclTest(string accessSpecifier, CX_CXXAccessSpecifier expectedAccessSpecifier) { + AssertNeedNewClangSharp(); + var inputContents = $@"struct MyStruct {{ {accessSpecifier}: @@ -32,6 +34,8 @@ public void AccessSpecDeclTest(string accessSpecifier, CX_CXXAccessSpecifier exp [Test] public void ClassTemplateDeclTest() { + AssertNeedNewClangSharp(); + var inputContents = $@"template class MyClass {{ @@ -51,6 +55,8 @@ class MyClass [Test] public void ClassTemplatePartialSpecializationDeclTest() { + AssertNeedNewClangSharp(); + var inputContents = $@"template class MyClass {{ @@ -78,6 +84,8 @@ class MyClass [Test] public void TemplateParameterPackTest() { + AssertNeedNewClangSharp(); + var inputContents = $@"template class tuple;