From d9bc5bec86aceb005191a898d2f905fc98e9d9fa Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 23 Aug 2013 04:19:00 +0300 Subject: [PATCH 01/10] Extended the check for duplicate names to ignore repeated operators since they cannot be renamed. Added an ignored test for an unrelated run-time issue. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/CheckDuplicatedNamesPass.cs | 8 ++++++-- tests/Basic/Basic.Tests.cs | 9 +++++++++ tests/Basic/Basic.cpp | 14 ++++++++++++++ tests/Basic/Basic.h | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Generator/Passes/CheckDuplicatedNamesPass.cs b/src/Generator/Passes/CheckDuplicatedNamesPass.cs index 82fc9b09..474415a0 100644 --- a/src/Generator/Passes/CheckDuplicatedNamesPass.cs +++ b/src/Generator/Passes/CheckDuplicatedNamesPass.cs @@ -37,7 +37,7 @@ namespace CppSharp.Passes return true; } - private bool UpdateName(Method method) + private bool UpdateName(Function method) { var @params = method.Parameters.Where(p => p.Kind != ParameterKind.IndirectReturnType) .Select(p => p.QualifiedType.ToString()); @@ -57,7 +57,11 @@ namespace CppSharp.Passes if (Count < methodCount+1) Count = methodCount+1; - method.Name += methodCount.ToString(CultureInfo.InvariantCulture); + if (method.IsOperator) + // TODO: turn into a method; append the original type (say, "signed long") of the last parameter to the type so that the user knows which overload is called + method.ExplicityIgnored = true; + else + method.Name += methodCount.ToString(CultureInfo.InvariantCulture); return true; } } diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index e4aaf48e..aa5f1010 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -52,5 +52,14 @@ public class BasicTests Assert.That(barSum.A, Is.EqualTo(bar.A + bar1.A)); Assert.That(barSum.B, Is.EqualTo(bar.B + bar1.B)); } + + [Test, Ignore] + public void TestLeftShiftOperator() + { + Foo2 foo2 = new Foo2(); + foo2.C = 2; + Foo2 result = foo2 << 3; + Assert.That(result.C, Is.EqualTo(16)); + } } \ No newline at end of file diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 1744ff77..438130ef 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -4,6 +4,20 @@ Foo::Foo() { } +Foo2& Foo2::operator <<(signed int i) +{ + Foo2 foo; + foo.C = C << i; + return foo; +} + +Foo2& Foo2::operator <<(signed long l) +{ + Foo2 foo; + foo.C = C << l; + return foo; +} + Bar::Bar() { } diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 7c4ae134..e40768e6 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -22,6 +22,9 @@ class DLL_API Foo2 : public Foo public: int C; + + Foo2& operator<<(signed int i); + Foo2& operator<<(signed long l); }; struct DLL_API Bar From 02559ed193aeaa58016f83bd1af115ca37ef4ed1 Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:04:37 +0100 Subject: [PATCH 02/10] Added better support for unary operators. --- src/AST/Method.cs | 6 ++++++ src/Generator/AST/Utils.cs | 8 ++++++++ src/Generator/Generators/CLI/CLISourcesTemplate.cs | 13 ++++++++----- tests/Basic/Basic.Tests.cs | 11 ++++++++++- tests/Basic/Basic.cpp | 8 ++++++++ tests/Basic/Basic.h | 1 + 6 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/AST/Method.cs b/src/AST/Method.cs index 7dfd67a5..5627b50e 100644 --- a/src/AST/Method.cs +++ b/src/AST/Method.cs @@ -10,6 +10,12 @@ namespace CppSharp.AST UsingDirective } + public enum CXXOperatorArity + { + Unary, + Binary + } + public enum CXXOperatorKind { None, diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index 75a72230..a4600c09 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -54,6 +54,14 @@ namespace CppSharp.AST public static class Operators { + public static CXXOperatorArity ClassifyOperator(Function function) + { + if (function.Parameters.Count == 1) + return CXXOperatorArity.Unary; + + return CXXOperatorArity.Binary; + } + public static string GetOperatorOverloadPair(CXXOperatorKind kind) { switch (kind) diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 5627e237..b13e854c 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -745,15 +745,18 @@ namespace CppSharp.Generators.CLI if (function.IsOperator) { - var kind = function.OperatorKind; - - var isBinary = function.Parameters.Count > 0; var opName = function.Name.Replace("operator", "").Trim(); - // Binary operator - if (isBinary) + switch (Operators.ClassifyOperator(function)) + { + case CXXOperatorArity.Unary: + WriteLine("{0} {1};", opName, @params[0].Name); + break; + case CXXOperatorArity.Binary: WriteLine("{0} {1} {2};", @params[0].Name, opName, @params[1].Name); + break; + } } else { diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index aa5f1010..5208be7a 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -44,7 +44,16 @@ public class BasicTests } [Test] - public void TestFunctionOperator() + public void TestUnaryOperator() + { + var bar = new Bar { A = 4, B = 7 }; + var barMinus = -bar; + Assert.That(barMinus.A, Is.EqualTo(-bar.A)); + Assert.That(barMinus.B, Is.EqualTo(-bar.B)); + } + + [Test] + public void TestBinaryOperator() { var bar = new Bar { A = 4, B = 7 }; var bar1 = new Bar { A = 5, B = 10 }; diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 438130ef..fe630c2a 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -95,6 +95,14 @@ const wchar_t* wcharFunction(const wchar_t* constWideChar) return constWideChar; } +Bar operator-(const Bar& b) +{ + Bar nb; + nb.A = -b.A; + nb.B = -b.B; + return nb; +} + Bar operator+(const Bar& b1, const Bar& b2) { Bar b; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index e40768e6..df964508 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -74,6 +74,7 @@ public: int RetEnum(Enum); }; +DLL_API Bar operator-(const Bar &); DLL_API Bar operator+(const Bar &, const Bar &); int DLL_API unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)); From 17fdab07cb7080baf135e638e544083547c037d9 Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:10:51 +0100 Subject: [PATCH 03/10] Only add missing operator overloads in C# generator. --- .../Passes/CheckOperatorsOverloads.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index 3cfb62ae..898fdd6d 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -24,18 +24,21 @@ namespace CppSharp.Passes // Check for C++ operators that cannot be represented in C#. CheckInvalidOperators(@class); - // The comparison operators, if overloaded, must be overloaded in pairs; - // that is, if == is overloaded, != must also be overloaded. The reverse - // is also true, and similar for < and >, and for <= and >=. + if (Driver.Options.IsCSharpGenerator) + { + // The comparison operators, if overloaded, must be overloaded in pairs; + // that is, if == is overloaded, != must also be overloaded. The reverse + // is also true, and similar for < and >, and for <= and >=. - HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.EqualEqual, - CXXOperatorKind.ExclaimEqual); + HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.EqualEqual, + CXXOperatorKind.ExclaimEqual); - HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.Less, - CXXOperatorKind.Greater); + HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.Less, + CXXOperatorKind.Greater); - HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.LessEqual, - CXXOperatorKind.GreaterEqual); + HandleMissingOperatorOverloadPair(@class, CXXOperatorKind.LessEqual, + CXXOperatorKind.GreaterEqual); + } return false; } From 2981c497dcab49cb4f1dd85842777050aa9716d2 Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:11:16 +0100 Subject: [PATCH 04/10] Remove extra newline from the output. --- src/Generator/Generators/CLI/CLIHeadersTemplate.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index c7a6842d..f9710ba4 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using CppSharp.AST; -using CppSharp.Generators.CSharp; using CppSharp.Types; namespace CppSharp.Generators.CLI @@ -632,7 +631,6 @@ namespace CppSharp.Generators.CLI } PopIndent(); - NewLine(); WriteLine("};"); PopBlock(NewLineKind.BeforeNextBlock); From 8bad119d7d9c68e8a57b8b1bef5c3dd92bb0281c Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:11:59 +0100 Subject: [PATCH 05/10] Fixed marshaling of pointers to classes in CLI generator. --- src/Generator/Generators/CLI/CLIMarshal.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 668c5dea..ba35d1c3 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -65,6 +65,15 @@ namespace CppSharp.Generators.CLI return true; } + Class @class; + if (pointee.Desugar().IsTagDecl(out @class)) + { + var instance = (pointer.IsReference) ? "&" + Context.ReturnVarName + : Context.ReturnVarName; + WriteClassInstance(@class, instance); + return true; + } + if (!pointee.Visit(this, quals)) return false; From 3771834bdd1eb76a4b82f2ea274aacf75d197fb2 Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:12:18 +0100 Subject: [PATCH 06/10] Fixed marshaling of function pointer typedefs in CLI generator. --- src/Generator/Generators/CLI/CLIMarshal.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index ba35d1c3..1ad00043 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -429,9 +429,9 @@ namespace CppSharp.Generators.CLI } FunctionType func; - if (decl.Type.IsPointerTo(out func)) + if (decl.Type.IsPointerTo(out func)) { - VisitDelegateType(func, typedef.Declaration.OriginalName); + VisitDelegateType(func, "::" + typedef.Declaration.QualifiedOriginalName); return true; } From 3f6dac4a507ec314894c4617fcd44b15ff5c16ed Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 16:12:49 +0100 Subject: [PATCH 07/10] Fixed parsing of function code gen info to be more robust. --- src/Parser/Parser.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index f70036fe..1917d65e 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -1621,6 +1621,8 @@ void Parser::WalkFunction(clang::FunctionDecl* FD, CppSharp::AST::Function^ F, // Skip the first argument as it's the return type. if (I == CGInfo.arg_begin()) continue; + if (Index >= F->Parameters->Count) + continue; F->Parameters[Index++]->IsIndirect = I->info.isIndirect(); } } From 0fcb5c02267b136e72d051a1beacee0c8b2c5de6 Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 23:24:09 +0100 Subject: [PATCH 08/10] Optimized/fixed marshaling for fields as there is no need to create a copied instance of the native object. --- src/Generator/Generators/CLI/CLIMarshal.cs | 3 ++- src/Generator/Generators/CLI/CLISourcesTemplate.cs | 1 + src/Generator/Generators/Marshal.cs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 1ad00043..551b4095 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -185,8 +185,9 @@ namespace CppSharp.Generators.CLI instance += "&"; instance += Context.ReturnVarName; + var needsCopy = !(Context.Declaration is Field); - if (@class.IsRefType) + if (@class.IsRefType && needsCopy) { var name = Generator.GeneratedIdentifier(Context.ReturnVarName); Context.SupportBefore.WriteLine("auto {0} = new ::{1}({2});", name, diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index b13e854c..6625d2a6 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -336,6 +336,7 @@ namespace CppSharp.Generators.CLI var ctx = new MarshalContext(Driver) { + Declaration = decl, ArgName = decl.Name, ReturnVarName = variable, ReturnType = decl.QualifiedType diff --git a/src/Generator/Generators/Marshal.cs b/src/Generator/Generators/Marshal.cs index 783179f5..8129b2be 100644 --- a/src/Generator/Generators/Marshal.cs +++ b/src/Generator/Generators/Marshal.cs @@ -19,6 +19,8 @@ namespace CppSharp.Generators public TextGenerator SupportBefore { get; private set; } public TextGenerator Return { get; private set; } + public Declaration Declaration { get; set; } + public string ReturnVarName { get; set; } public QualifiedType ReturnType { get; set; } From 36d520562ed4982e4e844b3b7f5bd5702ea2930e Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 25 Aug 2013 23:24:45 +0100 Subject: [PATCH 09/10] Use references instead of pointers when creating new operator overloads methods. --- src/Generator/Passes/CheckOperatorsOverloads.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index 898fdd6d..38680f64 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -63,7 +63,7 @@ namespace CppSharp.Passes var type = new PointerType() { QualifiedPointee = new QualifiedType(new TagType(@class)), - Modifier = PointerType.TypeModifier.Pointer + Modifier = PointerType.TypeModifier.LVReference }; @operator.Parameters.Insert(0, new Parameter From 3f7790c67dcab782b06a273eed02e65a34a7297c Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 27 Aug 2013 20:31:38 +0300 Subject: [PATCH 10/10] Fixed the incorrect C++ in the tests for left shift operators. The test still fails, though, now C is always 0. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/CheckDuplicatedNamesPass.cs | 9 +++++++-- tests/Basic/Basic.cpp | 4 ++-- tests/Basic/Basic.h | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Generator/Passes/CheckDuplicatedNamesPass.cs b/src/Generator/Passes/CheckDuplicatedNamesPass.cs index 474415a0..1241a988 100644 --- a/src/Generator/Passes/CheckDuplicatedNamesPass.cs +++ b/src/Generator/Passes/CheckDuplicatedNamesPass.cs @@ -8,12 +8,14 @@ namespace CppSharp.Passes { class DeclarationName { + public Driver Driver { get; set; } private readonly string Name; private readonly Dictionary methodSignatures; private int Count; - public DeclarationName(string name) + public DeclarationName(string name, Driver driver) { + Driver = driver; Name = name; methodSignatures = new Dictionary(); } @@ -58,8 +60,11 @@ namespace CppSharp.Passes Count = methodCount+1; if (method.IsOperator) + { // TODO: turn into a method; append the original type (say, "signed long") of the last parameter to the type so that the user knows which overload is called + Driver.Diagnostics.EmitWarning("Duplicate operator {0} ignored", method.Name); method.ExplicityIgnored = true; + } else method.Name += methodCount.ToString(CultureInfo.InvariantCulture); return true; @@ -136,7 +141,7 @@ namespace CppSharp.Passes // If the name is not yet on the map, then add it. if (!names.ContainsKey(fullName)) - names.Add(fullName, new DeclarationName(decl.Name)); + names.Add(fullName, new DeclarationName(decl.Name, Driver)); if (names[fullName].UpdateName(decl)) Driver.Diagnostics.EmitWarning("Duplicate name {0}, renamed to {1}", fullName, decl.Name); diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index fe630c2a..74fcfd40 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -4,14 +4,14 @@ Foo::Foo() { } -Foo2& Foo2::operator <<(signed int i) +Foo2 Foo2::operator<<(signed int i) { Foo2 foo; foo.C = C << i; return foo; } -Foo2& Foo2::operator <<(signed long l) +Foo2 Foo2::operator<<(signed long l) { Foo2 foo; foo.C = C << l; diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index df964508..109ab84a 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -23,8 +23,8 @@ public: int C; - Foo2& operator<<(signed int i); - Foo2& operator<<(signed long l); + Foo2 operator<<(signed int i); + Foo2 operator<<(signed long l); }; struct DLL_API Bar