From 547a9f28192140209cff6227b0c318cf7a42d19d Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 2 Jul 2019 00:48:02 +0300 Subject: [PATCH] Fix the passing of std::string by value std::string has a non-trivial copy constructor which was erroneously ignored. Fixes #867. Signed-off-by: Dimitar Dobrev --- src/CppParser/Parser.cpp | 8 ++- .../Passes/IgnoreSystemDeclarationsPass.cs | 57 ++----------------- tests/CSharp/CSharp.Tests.cs | 1 + tests/Common/Common.Tests.cs | 2 +- 4 files changed, 14 insertions(+), 54 deletions(-) diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index 37dada87..30dcb008 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -931,12 +931,16 @@ bool Parser::IsSupported(const clang::CXXMethodDecl* MD) { using namespace clang; + auto CopyCtor = llvm::dyn_cast(MD); + return !c->getSourceManager().isInSystemHeader(MD->getBeginLoc()) || - (isa(MD) && MD->getNumParams() == 0) || + (CopyCtor && (MD->getNumParams() == 0 || + (CopyCtor->isCopyConstructor() && !CopyCtor->isTrivial()))) || isa(MD) || (MD->getDeclName().isIdentifier() && ((MD->getName() == "c_str" && MD->getNumParams() == 0) || - (MD->getName() == "assign" && MD->getNumParams() == 1)) && + (MD->getName() == "assign" && MD->getNumParams() == 1 && + MD->parameters()[0]->getType()->isPointerType())) && supportedStdTypes.find(MD->getParent()->getName()) != supportedStdTypes.end()); } diff --git a/src/Generator/Passes/IgnoreSystemDeclarationsPass.cs b/src/Generator/Passes/IgnoreSystemDeclarationsPass.cs index 63f1d7e5..c1ff5f51 100644 --- a/src/Generator/Passes/IgnoreSystemDeclarationsPass.cs +++ b/src/Generator/Passes/IgnoreSystemDeclarationsPass.cs @@ -55,66 +55,21 @@ namespace CppSharp.Passes switch (@class.Name) { case "basic_string": - foreach (var method in @class.Methods.Where(m => !m.IsDestructor && - m.OriginalName != "c_str" && m.OriginalName != "assign")) - method.ExplicitlyIgnore(); - foreach (var basicString in GetCharSpecializations(@class)) - { - basicString.GenerationKind = GenerationKind.Generate; - foreach (var method in basicString.Methods) - { - if (method.IsDestructor || method.OriginalName == "c_str" || - (method.OriginalName == "assign" && - method.Parameters.Count == 1 && - method.Parameters[0].Type.IsPointerToPrimitiveType()) || - (method.IsConstructor && - !method.Parameters.Where(p => p.Kind == ParameterKind.Regular).Any())) - { - method.GenerationKind = GenerationKind.Generate; - method.Namespace.GenerationKind = GenerationKind.Generate; - method.InstantiatedFrom.GenerationKind = GenerationKind.Generate; - method.InstantiatedFrom.Namespace.GenerationKind = GenerationKind.Generate; - } - else - { - method.ExplicitlyIgnore(); - } - } - } - break; case "allocator": - foreach (var method in @class.Methods) - method.ExplicitlyIgnore(); - foreach (var allocator in GetCharSpecializations(@class)) - { - foreach (var method in allocator.Methods) - method.ExplicitlyIgnore(); - allocator.GenerationKind = GenerationKind.Generate; - allocator.TemplatedDecl.TemplatedDecl.GenerationKind = GenerationKind.Generate; - allocator.GenerationKind = GenerationKind.Generate; - } - break; case "char_traits": - foreach (var method in @class.Methods) - method.ExplicitlyIgnore(); - foreach (var charTraits in GetCharSpecializations(@class)) + @class.GenerationKind = GenerationKind.Generate; + foreach (var specialization in from s in @class.Specializations + let arg = s.Arguments[0].Type.Type.Desugar() + where arg.IsPrimitiveType(PrimitiveType.Char) + select s) { - foreach (var method in charTraits.Methods) - method.ExplicitlyIgnore(); - charTraits.GenerationKind = GenerationKind.Generate; - charTraits.TemplatedDecl.TemplatedDecl.GenerationKind = GenerationKind.Generate; + specialization.GenerationKind = GenerationKind.Generate; } break; } return true; } - private static IEnumerable GetCharSpecializations(Class @class) - { - return @class.Specializations.Where(s => - s.Arguments[0].Type.Type.Desugar().IsPrimitiveType(PrimitiveType.Char)); - } - public override bool VisitEnumDecl(Enumeration @enum) { if (!base.VisitEnumDecl(@enum)) diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index 5f6b88a8..a923a430 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -606,6 +606,7 @@ public unsafe class CSharpTests : GeneratorTestFixture } } + [Test] public void TestStdStringConstant() { Assert.That(CSharp.HasFreeConstant.AnotherUnit.STD_STRING_CONSTANT, Is.EqualTo("test")); diff --git a/tests/Common/Common.Tests.cs b/tests/Common/Common.Tests.cs index 65b9c455..1eadabf0 100644 --- a/tests/Common/Common.Tests.cs +++ b/tests/Common/Common.Tests.cs @@ -829,7 +829,7 @@ This is a very long string. This is a very long string. This is a very long stri } } - [Ignore("https://github.com/mono/CppSharp/issues/867")] + [Test] public void TestStdStringPassedByValue() { // when C++ memory is deleted, it's only marked as free but not immediadely freed