Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sources/ClangSharp.Interop/Extensions/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1834,6 +1834,8 @@ public static void DisposeOverriddenCursors(ReadOnlySpan<CXCursor> 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)
Expand Down
5 changes: 4 additions & 1 deletion sources/ClangSharp.Interop/clangsharp/clangsharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
24 changes: 23 additions & 1 deletion sources/ClangSharp/Cursors/Decls/Decl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,29 @@ private protected Decl(CXCursor handle, CXCursorKind expectedCursorKind, CX_Decl
_attrs = LazyList.Create<Attr>(Handle.NumAttrs, (i) => TranslationUnit.GetOrCreate<Attr>(Handle.GetAttr(unchecked((uint)i))));
_body = new ValueLazy<Stmt?>(() => !Handle.Body.IsNull ? TranslationUnit.GetOrCreate<Stmt>(Handle.Body) : null);
_canonicalDecl = new ValueLazy<Decl>(() => TranslationUnit.GetOrCreate<Decl>(Handle.CanonicalCursor));
_decls = LazyList.Create<Decl>(Handle.NumDecls, (i) => TranslationUnit.GetOrCreate<Decl>(Handle.GetDecl(unchecked((uint)i))));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW counting the decls (i.e. calling Handle.NumDecls) also shows up in the profile, although not nearly as prominent, so I also considered lazy-loading the count of LazyList instead of having to specify it up-front.

_decls = LazyList.Create<Decl>(Handle.NumDecls, (i) => TranslationUnit.GetOrCreate<Decl>(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<Decl>(cursors[i]);
}
}
else
{
for (var i = 0; i < list.Length; i++)
{
list[i] = TranslationUnit.GetOrCreate<Decl>(Handle.GetDecl(unchecked((uint)i)));
}
}
});
_describedTemplate = new ValueLazy<TemplateDecl?>(() => {
var describedTemplate = Handle.DescribedTemplate;
return describedTemplate.IsNull ? null : TranslationUnit.GetOrCreate<TemplateDecl>(describedTemplate);
Expand Down
4 changes: 2 additions & 2 deletions sources/ClangSharp/LazyList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace ClangSharp;

internal static class LazyList
{
public static LazyList<T> Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>(int count, Func<int, T> valueFactory)
public static LazyList<T> Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T>(int count, Func<int, T> valueFactory, Action<T[]>? allValuesFactory = null)
where T : class
{
if (count <= 0)
{
return LazyList<T>.Empty;
}
return new LazyList<T>(count, valueFactory);
return new LazyList<T>(count, valueFactory, allValuesFactory);
}

public static LazyList<T, TBase> Create<T, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TBase>(LazyList<TBase> list, int skip = -1, int take = -1)
Expand Down
34 changes: 15 additions & 19 deletions sources/ClangSharp/LazyList`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ internal sealed class LazyList<[DynamicallyAccessedMembers(DynamicallyAccessedMe
{
internal readonly T[] _items;
internal readonly Func<int, T> _valueFactory;
internal readonly Action<T[]>? _allValuesFactory;

public static readonly LazyList<T> Empty = new LazyList<T>(0, _ => null!);

public LazyList(int count, Func<int, T> valueFactory)
public LazyList(int count, Func<int, T> valueFactory, Action<T[]>? allValuesFactory = null)
{
_items = (count <= 0) ? [] : new T[count];
_valueFactory = valueFactory;
_allValuesFactory = allValuesFactory;
}

public T this[int index]
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand All @@ -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<T>.Default.Equals(currentItem, item))
{
return i;
Expand Down
22 changes: 22 additions & 0 deletions sources/libClangSharp/ClangSharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeclContext>(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);
Expand Down
2 changes: 2 additions & 0 deletions sources/libClangSharp/ClangSharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions tests/ClangSharp.UnitTests/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class CXCursorTest : TranslationUnitTest
[Test]
public void AttrKindSpelling()
{
AssertNeedNewClangSharp();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new native libClangSharp method makes a lot of tests fail because the new code is in a rather fundamental part of ClangSharp, not sure how to handle this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The simplest thing would be to use NativeLibrary.GetExport to try and resolve the new GetDecls API and fallback to the old logic if not present.

I can then fix that up to directly use the new API when I get the new libClangSharp published.


var inputContents =
$$"""
Expand Down
8 changes: 8 additions & 0 deletions tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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}:
Expand All @@ -32,6 +34,8 @@ public void AccessSpecDeclTest(string accessSpecifier, CX_CXXAccessSpecifier exp
[Test]
public void ClassTemplateDeclTest()
{
AssertNeedNewClangSharp();

var inputContents = $@"template<class T>
class MyClass
{{
Expand All @@ -51,6 +55,8 @@ class MyClass
[Test]
public void ClassTemplatePartialSpecializationDeclTest()
{
AssertNeedNewClangSharp();

var inputContents = $@"template<class T, class U>
class MyClass
{{
Expand Down Expand Up @@ -78,6 +84,8 @@ class MyClass<int, U>
[Test]
public void TemplateParameterPackTest()
{
AssertNeedNewClangSharp();

var inputContents = $@"template<class... Types>
class tuple;

Expand Down
Loading