diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 105459c9..3576f584 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -3632,7 +3632,7 @@ int clangsharp_Cursor_getNumTemplateArguments(CXCursor C) { if (const FunctionDecl* FD = dyn_cast(D)) { const TemplateArgumentList* TAL = FD->getTemplateSpecializationArgs(); - return TAL && TAL->size(); + return TAL ? TAL->size() : 0; } if (FunctionTemplateDecl* FTD = const_cast(dyn_cast(D))) { @@ -4522,9 +4522,9 @@ CX_TemplateArgument clangsharp_Cursor_getTemplateArgument(CXCursor C, unsigned i } } - if (const VarTemplatePartialSpecializationDecl* VTPSD = dyn_cast(D)) { - if (i < VTPSD->getTemplateArgs().size()) { - const TemplateArgument* TA = &VTPSD->getTemplateArgs()[i]; + if (const VarTemplateSpecializationDecl* VTSD = dyn_cast(D)) { + if (i < VTSD->getTemplateArgs().size()) { + const TemplateArgument* TA = &VTSD->getTemplateArgs()[i]; return MakeCXTemplateArgument(TA, getCursorTU(C)); } } diff --git a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs index bf6aa056..b9f25959 100644 --- a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs +++ b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs @@ -1,7 +1,9 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. using System; +using System.Globalization; using System.Linq; +using System.Text.RegularExpressions; using ClangSharp.Interop; using NUnit.Framework; using static ClangSharp.Interop.CX_CXXAccessSpecifier; @@ -98,6 +100,50 @@ class tuple; Assert.That(packElements[1].AsType.AsString, Is.EqualTo("long")); } + [Test] + public void FunctionTemplateSpecializationArgsTest() + { + SkipUntilNativeRebuild(); + + var inputContents = $@"template +void MyFunction(T t, U u); + +template<> +void MyFunction(int t, float u); +"; + + using var translationUnit = CreateTranslationUnit(inputContents); + + var functionDecl = translationUnit.TranslationUnitDecl.Decls.OfType().Single((functionDecl) => functionDecl.TemplateSpecializationArgs.Count != 0); + + Assert.That(functionDecl.TemplateSpecializationArgs.Count, Is.EqualTo(2)); + Assert.That(functionDecl.TemplateSpecializationArgs[0].AsType.AsString, Is.EqualTo("int")); + Assert.That(functionDecl.TemplateSpecializationArgs[1].AsType.AsString, Is.EqualTo("float")); + } + + [Test] + public void VarTemplateSpecializationArgsTest() + { + SkipUntilNativeRebuild(); + + var inputContents = $@"template +constexpr int MyVar = 0; + +template<> +constexpr int MyVar = 1; +"; + + using var translationUnit = CreateTranslationUnit(inputContents); + + var varTemplateSpecializationDecl = translationUnit.TranslationUnitDecl.Decls.OfType().Single(); + + Assert.That(varTemplateSpecializationDecl.TemplateArgs.Count, Is.EqualTo(2)); + Assert.That(varTemplateSpecializationDecl.TemplateArgs[0].IsNull, Is.False); + Assert.That(varTemplateSpecializationDecl.TemplateArgs[1].IsNull, Is.False); + Assert.That(varTemplateSpecializationDecl.TemplateArgs[0].AsType.AsString, Is.EqualTo("int")); + Assert.That(varTemplateSpecializationDecl.TemplateArgs[1].AsType.AsString, Is.EqualTo("float")); + } + [Test] public void IsPodTest() { @@ -221,4 +267,20 @@ enum E { checkField("H", -1, 18446744073709551615UL, true); }); } + + // The fix for these lives in the native libClangSharp shim (clangsharp_Cursor_getNumTemplateArguments + // and clangsharp_Cursor_getTemplateArgument). The pinned 21.1 prebuilt native package predates it, so + // skip until the native lib is rebuilt for a newer libClang. Rebuilding off 21.1 auto-unskips these. + private static void SkipUntilNativeRebuild() + { + using var versionString = clang.getClangVersion(); + var match = Regex.Match(versionString.ToString(), @"version (\d+)\.(\d+)"); + + if (match.Success + && (int.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture) == 21) + && (int.Parse(match.Groups[2].ValueSpan, CultureInfo.InvariantCulture) == 1)) + { + Assert.Ignore("Requires a native libClangSharp rebuild that includes the template-argument accessor fix; the pinned 21.1 prebuilt package predates it. Remove this guard once libClang moves off 21.1 and the native lib is rebuilt."); + } + } }