diff --git a/Directory.Build.props b/Directory.Build.props index 4797b4f0..39a8f51d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -47,7 +47,7 @@ 17.0.0 ClangSharp ClangSharp - 18.1.0.3 + 18.1.0.4 rc1 pr diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 5558ed50..882eba52 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -20,7 +20,7 @@ $ErrorActionPreference = "Stop" function Build() { $logFile = Join-Path -Path $LogDir -ChildPath "$configuration\build.binlog" - & dotnet build -c "$configuration" --no-restore -v "$verbosity" /bl:"$logFile" /err "$properties" "$solution" + & dotnet build -c "$configuration" --no-restore -v "$verbosity" /bl:"$logFile" /err $properties "$solution" if ($LastExitCode -ne 0) { throw "'Build' failed for '$solution'" @@ -57,7 +57,7 @@ function Help() { function Pack() { $logFile = Join-Path -Path $LogDir -ChildPath "$configuration\pack.binlog" - & dotnet pack -c "$configuration" --no-build --no-restore -v "$verbosity" /bl:"$logFile" /err "$properties" "$solution" + & dotnet pack -c "$configuration" --no-build --no-restore -v "$verbosity" /bl:"$logFile" /err $properties "$solution" if ($LastExitCode -ne 0) { throw "'Pack' failed for '$solution'" @@ -66,7 +66,7 @@ function Pack() { function Restore() { $logFile = Join-Path -Path $LogDir -ChildPath "$configuration\restore.binlog" - & dotnet restore -v "$verbosity" /bl:"$logFile" /err "$properties" "$solution" + & dotnet restore -v "$verbosity" /bl:"$logFile" /err $properties "$solution" if ($LastExitCode -ne 0) { throw "'Restore' failed for '$solution'" @@ -75,7 +75,7 @@ function Restore() { function Test() { $logFile = Join-Path -Path $LogDir -ChildPath "$configuration\test.binlog" - & dotnet test -c "$configuration" --no-build --no-restore -v "$verbosity" /bl:"$logFile" /err "$properties" "$solution" + & dotnet test -c "$configuration" --no-build --no-restore -v "$verbosity" /bl:"$logFile" /err $properties "$solution" if ($LastExitCode -ne 0) { throw "'Test' failed for '$solution'" diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index 91979977..540329f0 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -1043,6 +1043,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Type_getOriginalType", ExactSpelling = true)] public static extern CXType Type_getOriginalType(CXType CT); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Type_getSubstTemplateTypeParamAssociatedDecl", ExactSpelling = true)] + public static extern CXCursor Type_getSubstTemplateTypeParamAssociatedDecl(CXType CT); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Type_getOwnedTagDecl", ExactSpelling = true)] public static extern CXCursor Type_getOwnedTagDecl(CXType CT); diff --git a/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs b/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs index d05c90b3..0a33d680 100644 --- a/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs +++ b/sources/ClangSharp.PInvokeGenerator/Abstractions/FunctionOrDelegateDesc.cs @@ -21,6 +21,7 @@ internal struct FunctionOrDelegateDesc public bool HasBody { get; set; } public bool IsInherited { get; set; } public bool NeedsUnscopedRef { get; set; } + public string[]? ParameterTypes { get; set; } public bool IsVirtual { diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs index 712f8c81..8380a582 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs @@ -372,6 +372,12 @@ public void BeginFunctionOrDelegate(in FunctionOrDelegateDesc desc, ref bool isM Write(desc.ParentName); Write('.'); Write(desc.EscapedName); + if (desc.ParameterTypes is not null) + { + Write('('); + Write(string.Join(", ", desc.ParameterTypes)); + Write(')'); + } WriteLine("\" />"); } else diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index c1e270f5..2e37bb02 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -501,6 +501,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) var name = GetRemappedCursorName(functionDecl); var cxxMethodDecl = functionDecl as CXXMethodDecl; + uint overloadCount = 0; if (cxxMethodDecl is not null and CXXConstructorDecl) { @@ -509,6 +510,11 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) name = GetRemappedCursorName(parent); } + if (cxxMethodDecl is not null) + { + overloadCount = GetOverloadCount(cxxMethodDecl); + } + var isManualImport = _config.WithManualImports.Contains(name); var className = name; @@ -622,6 +628,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) } }, CustomAttrGeneratorData = (functionDecl, _outputBuilder, this), + ParameterTypes = overloadCount > 1 ? functionDecl.Parameters.Select(param => GetTargetTypeName(param, out var _)).ToArray() : null, }; Debug.Assert(_outputBuilder is not null); @@ -1404,7 +1411,15 @@ private void VisitRecordDecl(RecordDecl recordDecl) var className = GetClass(uuidName); _testOutputBuilder.AddUsingDirective("System"); - _testOutputBuilder.AddUsingDirective($"static {GetNamespace(className)}.{className}"); + + if (_config.DontUseUsingStaticsForGuidMember) + { + _testOutputBuilder.AddUsingDirective($"{GetNamespace(className)}"); + } + else + { + _testOutputBuilder.AddUsingDirective($"static {GetNamespace(className)}.{className}"); + } _testOutputBuilder.WriteIndented("/// Validates that the of the ExcludedNames public bool StripEnumMemberTypeName => _options.HasFlag(PInvokeGeneratorConfigurationOptions.StripEnumMemberTypeName); + public bool DontUseUsingStaticsForGuidMember => _options.HasFlag(PInvokeGeneratorConfigurationOptions.DontUseUsingStaticsForGuidMember); + public string HeaderText => _headerText; [AllowNull] diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs index c2a34293..cd77e71c 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGeneratorConfigurationOptions.cs @@ -88,4 +88,6 @@ public enum PInvokeGeneratorConfigurationOptions : long GenerateGenericPointerWrapper = 1L << 38, StripEnumMemberTypeName = 1L << 39, + + DontUseUsingStaticsForGuidMember = 1L << 40, } diff --git a/sources/ClangSharp/Cursors/Decls/TemplateTypeParmDecl.cs b/sources/ClangSharp/Cursors/Decls/TemplateTypeParmDecl.cs index f68532c1..ca0f4b1f 100644 --- a/sources/ClangSharp/Cursors/Decls/TemplateTypeParmDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/TemplateTypeParmDecl.cs @@ -5,13 +5,14 @@ using ClangSharp.Interop; using static ClangSharp.Interop.CXCursorKind; using static ClangSharp.Interop.CX_DeclKind; +using static ClangSharp.Interop.CXTypeKind; namespace ClangSharp; public sealed class TemplateTypeParmDecl : TypeDecl { private readonly Lazy> _associatedConstraints; - private readonly Lazy _defaultArgument; + private readonly Lazy _defaultArgument; internal TemplateTypeParmDecl(CXCursor handle) : base(handle, CXCursor_TemplateTypeParameter, CX_DeclKind_TemplateTypeParm) { @@ -27,12 +28,15 @@ internal TemplateTypeParmDecl(CXCursor handle) : base(handle, CXCursor_TemplateT return associatedConstraints; }); - _defaultArgument = new Lazy(() => TranslationUnit.GetOrCreate(Handle.DefaultArgType)); + _defaultArgument = new Lazy(() => { + CXType defaultArgType = Handle.DefaultArgType; + return defaultArgType.kind == CXType_Invalid ? null : TranslationUnit.GetOrCreate(defaultArgType); + }); } public IReadOnlyList AssociatedConstraints => _associatedConstraints.Value; - public Type DefaultArgument => _defaultArgument.Value; + public Type? DefaultArgument => _defaultArgument.Value; public bool DefaultArgumentWasInherited => Handle.HasInheritedDefaultArg; diff --git a/sources/ClangSharp/Types/SubstTemplateTypeParmType.cs b/sources/ClangSharp/Types/SubstTemplateTypeParmType.cs index 517d387b..d09e2a5c 100644 --- a/sources/ClangSharp/Types/SubstTemplateTypeParmType.cs +++ b/sources/ClangSharp/Types/SubstTemplateTypeParmType.cs @@ -9,14 +9,21 @@ namespace ClangSharp; public sealed class SubstTemplateTypeParmType : Type { + private readonly Lazy _associatedDecl; private readonly Lazy _replacedParameter; internal SubstTemplateTypeParmType(CXType handle) : base(handle, CXType_Unexposed, CX_TypeClass_SubstTemplateTypeParm) { + _associatedDecl = new Lazy(() => { + CXCursor cursor = clangsharp.Type_getSubstTemplateTypeParamAssociatedDecl(Handle); + return cursor.IsNull ? null : TranslationUnit.GetOrCreate(cursor); + }); _replacedParameter = new Lazy(() => TranslationUnit.GetOrCreate(Handle.OriginalType)); } public TemplateTypeParmType ReplacedParameter => _replacedParameter.Value; public Type ReplacementType => Desugar; + + public Decl? AssociatedDecl => _associatedDecl.Value; } diff --git a/sources/ClangSharpPInvokeGenerator/Program.cs b/sources/ClangSharpPInvokeGenerator/Program.cs index 322ef1e4..8bad0657 100644 --- a/sources/ClangSharpPInvokeGenerator/Program.cs +++ b/sources/ClangSharpPInvokeGenerator/Program.cs @@ -444,6 +444,13 @@ public static void Run(InvocationContext context) break; } + case "exclude-using-statics-for-guid-members": + case "dont-use-using-statics-for-guid-members": + { + configOptions |= PInvokeGeneratorConfigurationOptions.DontUseUsingStaticsForGuidMember; + break; + } + // VTBL Options case "explicit-vtbls": diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 5880900c..d0f0c8a9 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -26,10 +26,38 @@ using namespace clang::cxstring; using namespace clang::cxtu; using namespace clang::cxtype; +CXTemplateArgumentKind ConvertTemplateArgumentKind(TemplateArgument::ArgKind kind) { + switch (kind) { + case TemplateArgument::Null: + return CXTemplateArgumentKind_Null; + case TemplateArgument::Type: + return CXTemplateArgumentKind_Type; + case TemplateArgument::Declaration: + return CXTemplateArgumentKind_Declaration; + case TemplateArgument::NullPtr: + return CXTemplateArgumentKind_NullPtr; + case TemplateArgument::Integral: + return CXTemplateArgumentKind_Integral; + case TemplateArgument::StructuralValue: + // Does not exist in CXTemplateArgumentKind + return CXTemplateArgumentKind_Invalid; + case TemplateArgument::Template: + return CXTemplateArgumentKind_Template; + case TemplateArgument::TemplateExpansion: + return CXTemplateArgumentKind_TemplateExpansion; + case TemplateArgument::Expression: + return CXTemplateArgumentKind_Expression; + case TemplateArgument::Pack: + return CXTemplateArgumentKind_Pack; + default: + return CXTemplateArgumentKind_Invalid; + } +} + CX_TemplateArgument MakeCXTemplateArgument(const TemplateArgument* TA, CXTranslationUnit TU, bool needsDispose = false) { if (TA) { assert(TU && "Invalid arguments!"); - return { static_cast(TA->getKind()), (needsDispose ? 1 : 0), TA, TU }; + return { ConvertTemplateArgumentKind(TA->getKind()), (needsDispose ? 1 : 0), TA, TU }; } return { }; @@ -1009,15 +1037,19 @@ CXCursor clangsharp_Cursor_getDefaultArg(CXCursor C) { } CXType clangsharp_Cursor_getDefaultArgType(CXCursor C) { + QualType QT; + if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); if (const TemplateTypeParmDecl* TTPD = dyn_cast(D)) { - return MakeCXType(TTPD->getDefaultArgument(), getCursorTU(C)); + if (TTPD->hasDefaultArgument()) { + QT = TTPD->getDefaultArgument(); + } } } - return MakeCXType(QualType(), getCursorTU(C)); + return MakeCXType(QT, getCursorTU(C)); } CXCursor clangsharp_Cursor_getDefinition(CXCursor C) { @@ -5369,6 +5401,17 @@ CXType clangsharp_Type_getOriginalType(CXType CT) { return MakeCXType(QualType(), GetTypeTU(CT)); } +CXCursor clangsharp_Type_getSubstTemplateTypeParamAssociatedDecl(CXType CT) { + QualType T = GetQualType(CT); + const Type* TP = T.getTypePtrOrNull(); + + if (const SubstTemplateTypeParmType* STTPT = dyn_cast(TP)) { + return MakeCXCursor(STTPT->getAssociatedDecl(), GetTypeTU(CT)); + } + + clang_getNullCursor(); +} + CXCursor clangsharp_Type_getOwnedTagDecl(CXType CT) { QualType T = GetQualType(CT); const Type* TP = T.getTypePtrOrNull(); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 01120c2b..b7ea675a 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -841,6 +841,8 @@ CLANGSHARP_LINKAGE int clangsharp_Type_getNumRows(CXType CT); CLANGSHARP_LINKAGE CXType clangsharp_Type_getOriginalType(CXType CT); +CLANGSHARP_LINKAGE CXCursor clangsharp_Type_getSubstTemplateTypeParamAssociatedDecl(CXType CT); + CLANGSHARP_LINKAGE CXCursor clangsharp_Type_getOwnedTagDecl(CXType CT); CLANGSHARP_LINKAGE CXType clangsharp_Type_getPointeeType(CXType CT); diff --git a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs index 067280f1..e216b73b 100644 --- a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs +++ b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs @@ -74,4 +74,27 @@ class MyClass var templateParameter = classTemplatePartialSpecializationDecl.TemplateParameters.Single(); Assert.That(templateParameter.Name, Is.EqualTo("U")); } + + [Test] + [Ignore("TODO: LibClangSharp needs to be recompiled first")] + public void TemplateParameterPackTest() + { + var inputContents = $@"template +class tuple; + +tuple SomeFunction(); +"; + + using var translationUnit = CreateTranslationUnit(inputContents); + + var functionDecl = translationUnit.TranslationUnitDecl.Decls.OfType().Single(); + var tupleDecl = functionDecl.ReturnType.AsCXXRecordDecl as ClassTemplateSpecializationDecl; + Assert.That(tupleDecl, Is.Not.Null); + Assert.That(tupleDecl!.TemplateArgs.Count, Is.EqualTo(1)); + + var packElements = tupleDecl.TemplateArgs[0].PackElements; + Assert.That(packElements.Count, Is.EqualTo(2)); + Assert.That(packElements[0].AsType.AsString, Is.EqualTo("int")); + Assert.That(packElements[1].AsType.AsString, Is.EqualTo("long")); + } }