Skip to content

Commit e48a3ee

Browse files
Merge pull request #690 from dalexsoto/dev/alex/fix-cursor-issue
Fix ArgumentOutOfRangeException in Type and Decl constructors during ObjC AST traversal
2 parents 4a10f3f + 06f9f4b commit e48a3ee

3 files changed

Lines changed: 493 additions & 8 deletions

File tree

sources/ClangSharp/Cursors/Decls/Decl.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ public class Decl : Cursor
2626

2727
private protected Decl(CXCursor handle, CXCursorKind expectedCursorKind, CX_DeclKind expectedDeclKind) : base(handle, expectedCursorKind)
2828
{
29-
if ((handle.DeclKind == CX_DeclKind_Invalid) || (handle.DeclKind != expectedDeclKind))
29+
// When the native libClangSharp doesn't have a mapping for a declaration kind,
30+
// it returns CX_DeclKind_Invalid. When the default case in Decl.Create() constructs
31+
// a generic Decl with expectedDeclKind == CX_DeclKind_Invalid, we should allow it
32+
// rather than throwing, so that unknown declaration kinds degrade gracefully to a
33+
// base Decl wrapper instead of crashing the entire traversal.
34+
if (handle.DeclKind != expectedDeclKind)
3035
{
3136
throw new ArgumentOutOfRangeException(nameof(handle));
3237
}

sources/ClangSharp/Types/Type.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,29 @@ public unsafe class Type : IEquatable<Type>
2020

2121
protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedTypeClass, params ReadOnlySpan<CXTypeKind> additionalExpectedKinds)
2222
{
23-
#if NET10_0_OR_GREATER
24-
if (handle.kind != expectedKind && !additionalExpectedKinds.Contains(handle.kind))
25-
#else
26-
if (handle.kind != expectedKind && !Contains(additionalExpectedKinds, handle.kind))
27-
#endif
23+
if ((handle.TypeClass == CX_TypeClass_Invalid) || (handle.TypeClass != expectedTypeClass))
2824
{
2925
throw new ArgumentOutOfRangeException(nameof(handle));
3026
}
3127

32-
if ((handle.TypeClass == CX_TypeClass_Invalid) || (handle.TypeClass != expectedTypeClass))
28+
// CXTypeKind is validated after TypeClass because libclang's CXTypeKind uses a
29+
// coarser classification than libClangSharp's CX_TypeClass. For example, libclang
30+
// may return CXType_ObjCId or CXType_Unexposed for a type that libClangSharp
31+
// correctly classifies as CX_TypeClass_Attributed via the Clang AST. Since
32+
// TypeClass is the authoritative classifier and already validated above, a
33+
// CXTypeKind mismatch is not fatal.
34+
var kindMatches = handle.kind == expectedKind
35+
#if NET10_0_OR_GREATER
36+
|| additionalExpectedKinds.Contains(handle.kind);
37+
#else
38+
|| Contains(additionalExpectedKinds, handle.kind);
39+
#endif
40+
41+
if (!kindMatches)
3342
{
34-
throw new ArgumentOutOfRangeException(nameof(handle));
43+
Debug.WriteLine($"Unexpected CXTypeKind for {handle.TypeClass}: {handle.kind}.");
3544
}
45+
3646
Handle = handle;
3747

3848
_asString = new ValueLazy<string>(Handle.Spelling.ToString);

0 commit comments

Comments
 (0)