Browse Source

Added support for explicit conversion operators and added new pass which will create implicit and explicit conversion operators out of single argument constructors.

Conflicts:
	src/Generator/Passes/CheckAmbiguousFunctions.cs
	src/Generator/Passes/CheckOperatorsOverloads.cs
pull/234/head
Elias Holzer 11 years ago committed by triton
parent
commit
474f82b513
  1. 3
      src/AST/Method.cs
  2. 2
      src/Generator/AST/Utils.cs
  3. 4
      src/Generator/Driver.cs
  4. 6
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  5. 6
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  6. 3
      src/Generator/Generators/CLI/CLITextTemplate.cs
  7. 17
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  8. 7
      src/Generator/Options.cs
  9. 2
      src/Generator/Passes/CheckAmbiguousFunctions.cs
  10. 3
      src/Generator/Passes/CheckOperatorsOverloads.cs
  11. 61
      src/Generator/Passes/ConstructorToConversionOperatorPass.cs
  12. 10
      tests/Basic/Basic.Tests.cs
  13. 1
      tests/Basic/Basic.cs
  14. 28
      tests/Basic/Basic.h
  15. 3
      tests/CSharpTemp/CSharpTemp.cs

3
src/AST/Method.cs

@ -64,7 +64,8 @@ namespace CppSharp.AST
Call, Call,
Subscript, Subscript,
Conditional, Conditional,
Conversion Conversion,
ExplicitConversion
} }
/// <summary> /// <summary>

2
src/Generator/AST/Utils.cs

@ -200,6 +200,8 @@ namespace CppSharp.AST
case CXXOperatorKind.Conversion: case CXXOperatorKind.Conversion:
return "implicit operator"; return "implicit operator";
case CXXOperatorKind.ExplicitConversion:
return "explicit operator";
} }
throw new NotSupportedException(); throw new NotSupportedException();

4
src/Generator/Driver.cs

@ -277,6 +277,10 @@ namespace CppSharp
TranslationUnitPasses.AddPass(new CheckStaticClass()); TranslationUnitPasses.AddPass(new CheckStaticClass());
TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass());
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
if (Options.GenerateConversionOperators)
TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass());
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass()); TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass());
TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance()); TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance());

6
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -681,8 +681,12 @@ namespace CppSharp.Generators.CLI
if (method.IsStatic || isBuiltinOperator) if (method.IsStatic || isBuiltinOperator)
Write("static "); Write("static ");
if (method.OperatorKind == CXXOperatorKind.ExplicitConversion)
Write("explicit ");
if (method.IsConstructor || method.IsDestructor || if (method.IsConstructor || method.IsDestructor ||
method.OperatorKind == CXXOperatorKind.Conversion) method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
Write("{0}(", GetMethodName(method)); Write("{0}(", GetMethodName(method));
else else
Write("{0} {1}(", method.ReturnType, method.Name); Write("{0} {1}(", method.ReturnType, method.Name);

6
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -691,7 +691,8 @@ namespace CppSharp.Generators.CLI
PushBlock(CLIBlockKind.Method, method); PushBlock(CLIBlockKind.Method, method);
if (method.IsConstructor || method.IsDestructor || if (method.IsConstructor || method.IsDestructor ||
method.OperatorKind == CXXOperatorKind.Conversion) method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
Write("{0}::{1}(", QualifiedIdentifier(@class), GetMethodName(method)); Write("{0}::{1}(", QualifiedIdentifier(@class), GetMethodName(method));
else else
Write("{0} {1}::{2}(", method.ReturnType, QualifiedIdentifier(@class), Write("{0} {1}::{2}(", method.ReturnType, QualifiedIdentifier(@class),
@ -865,7 +866,8 @@ namespace CppSharp.Generators.CLI
Write("auto {0}{1} = ",(function.ReturnType.Type.IsReference())? "&": string.Empty, Write("auto {0}{1} = ",(function.ReturnType.Type.IsReference())? "&": string.Empty,
Generator.GeneratedIdentifier("ret")); Generator.GeneratedIdentifier("ret"));
if (function.OperatorKind == CXXOperatorKind.Conversion) if (function.OperatorKind == CXXOperatorKind.Conversion ||
function.OperatorKind == CXXOperatorKind.ExplicitConversion)
{ {
var method = function as Method; var method = function as Method;
var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var typePrinter = new CppTypePrinter(Driver.TypeDatabase);

3
src/Generator/Generators/CLI/CLITextTemplate.cs

@ -96,7 +96,8 @@ namespace CppSharp.Generators.CLI
public string GetMethodName(Method method) public string GetMethodName(Method method)
{ {
if (method.OperatorKind == CXXOperatorKind.Conversion) if (method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
return "operator " + method.ConversionType; return "operator " + method.ConversionType;
if (method.IsConstructor || method.IsDestructor) if (method.IsConstructor || method.IsDestructor)

17
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -2033,7 +2033,8 @@ namespace CppSharp.Generators.CSharp
else if (method.ExplicitInterfaceImpl != null) else if (method.ExplicitInterfaceImpl != null)
Write("{0} {1}.{2}(", method.OriginalReturnType, Write("{0} {1}.{2}(", method.OriginalReturnType,
method.ExplicitInterfaceImpl.Name, functionName); method.ExplicitInterfaceImpl.Name, functionName);
else if (method.OperatorKind == CXXOperatorKind.Conversion) else if (method.OperatorKind == CXXOperatorKind.Conversion ||
method.OperatorKind == CXXOperatorKind.ExplicitConversion)
Write("{0} {1}(", functionName, method.OriginalReturnType); Write("{0} {1}(", functionName, method.OriginalReturnType);
else else
Write("{0} {1}(", method.OriginalReturnType, functionName); Write("{0} {1}(", method.OriginalReturnType, functionName);
@ -2156,11 +2157,25 @@ namespace CppSharp.Generators.CSharp
private void GenerateOperator(Method method, Class @class) private void GenerateOperator(Method method, Class @class)
{ {
if (method.IsSynthetized) if (method.IsSynthetized)
{
if (method.Kind == CXXMethodKind.Conversion)
{
// To avoid ambiguity when having the multiple inheritance pass enabled
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
if (@interface != null)
WriteLine("return new {0}(({2}){1});", method.ConversionType,
method.Parameters[0].Name, @interface.Name);
else
WriteLine("return new {0}({1});", method.ConversionType,
method.Parameters[0].Name);
}
else
{ {
var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind); var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind);
WriteLine("return !({0} {1} {2});", method.Parameters[0].Name, WriteLine("return !({0} {1} {2});", method.Parameters[0].Name,
@operator, method.Parameters[1].Name); @operator, method.Parameters[1].Name);
}
return; return;
} }

7
src/Generator/Options.cs

@ -112,6 +112,13 @@ namespace CppSharp
/// </summary> /// </summary>
public bool GeneratePropertiesAdvanced; public bool GeneratePropertiesAdvanced;
/// <summary>
/// If set to true the generator will use ConstructorToConversionOperatorPass to
/// create implicit and explicit conversion operators out of single argument
/// constructors.
/// </summary>
public bool GenerateConversionOperators;
//List of include directories that are used but not generated //List of include directories that are used but not generated
public List<string> NoGenIncludeDirs; public List<string> NoGenIncludeDirs;

2
src/Generator/Passes/CheckAmbiguousFunctions.cs

@ -37,6 +37,8 @@ namespace CppSharp.Passes
{ {
if (function.OperatorKind == CXXOperatorKind.Conversion) if (function.OperatorKind == CXXOperatorKind.Conversion)
continue; continue;
if (function.OperatorKind == CXXOperatorKind.ExplicitConversion)
continue;
if (overload == function) continue; if (overload == function) continue;

3
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -197,8 +197,9 @@ namespace CppSharp.Passes
// The array indexing operator can be overloaded // The array indexing operator can be overloaded
case CXXOperatorKind.Subscript: case CXXOperatorKind.Subscript:
// The conversion operator can be overloaded // The conversion operators can be overloaded
case CXXOperatorKind.Conversion: case CXXOperatorKind.Conversion:
case CXXOperatorKind.ExplicitConversion:
return true; return true;
// The comparison operators can be overloaded if their return type is bool // The comparison operators can be overloaded if their return type is bool

61
src/Generator/Passes/ConstructorToConversionOperatorPass.cs

@ -0,0 +1,61 @@
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
namespace CppSharp.Passes
{
/// <summary>
/// This pass will create conversion operators out of single argument
/// constructors.
/// </summary>
public class ConstructorToConversionOperatorPass : TranslationUnitPass
{
public override bool VisitMethodDecl(Method method)
{
if (!method.IsConstructor)
return false;
if (method.IsCopyConstructor)
return false;
if (method.Parameters.Count != 1)
return false;
var parameter = method.Parameters[0];
var parameterType = parameter.Type as PointerType;
if (parameterType == null)
return false;
if (!parameterType.IsReference)
return false;
var qualifiedPointee = parameterType.QualifiedPointee;
if (!qualifiedPointee.Qualifiers.IsConst)
return false;
Class castFromClass;
if (!qualifiedPointee.Type.IsTagDecl(out castFromClass))
return false;
var castToClass = method.OriginalNamespace as Class;
if (castToClass == null)
return false;
if (castFromClass == castToClass)
return false;
var operatorKind = CXXOperatorKind.Conversion;
if (method.Signature.StartsWith("explicit", System.StringComparison.OrdinalIgnoreCase))
operatorKind = CXXOperatorKind.ExplicitConversion;
var castToType = new TagType(castToClass);
var qualifiedCastToType = new QualifiedType(castToType);
var conversionOperator = new Method()
{
Name = Operators.GetOperatorIdentifier(operatorKind),
Namespace = castFromClass,
Kind = CXXMethodKind.Conversion,
IsSynthetized = true,
ConversionType = qualifiedCastToType,
ReturnType = qualifiedCastToType
};
conversionOperator.OperatorKind = operatorKind;
castFromClass.Methods.Add(conversionOperator);
return true;
}
}
}

10
tests/Basic/Basic.Tests.cs

@ -293,5 +293,15 @@ public class BasicTests : GeneratorTestFixture
Assert.That(@class.Width, Is.EqualTo(640)); Assert.That(@class.Width, Is.EqualTo(640));
Assert.That(@class.Height, Is.EqualTo(480)); Assert.That(@class.Height, Is.EqualTo(480));
} }
[Test]
public unsafe void TestSingleArgumentCtorToCastOperator()
{
var classA = new ClassA(10);
ClassB classB = classA;
Assert.AreEqual(classA.Value, classB.Value);
ClassC classC = (ClassC)classB;
Assert.AreEqual(classB.Value, classC.Value);
}
} }

1
tests/Basic/Basic.cs

@ -21,6 +21,7 @@ namespace CppSharp.Tests
driver.Options.GenerateCopyConstructors = true; driver.Options.GenerateCopyConstructors = true;
driver.Options.MarshalCharAsManagedChar = true; driver.Options.MarshalCharAsManagedChar = true;
driver.Options.GenerateProperties = true; driver.Options.GenerateProperties = true;
driver.Options.GenerateConversionOperators = true;
} }
public override void Preprocess(Driver driver, ASTContext ctx) public override void Preprocess(Driver driver, ASTContext ctx)

28
tests/Basic/Basic.h

@ -422,3 +422,31 @@ struct DLL_API TestGetterSetterToProperties
int TestGetterSetterToProperties::getWidth() { return 640; } int TestGetterSetterToProperties::getWidth() { return 640; }
int TestGetterSetterToProperties::getHeight() { return 480; } int TestGetterSetterToProperties::getHeight() { return 480; }
// Tests conversion operators of classes
class DLL_API ClassA
{
public:
ClassA(int value) { Value = value; }
int Value;
};
class DLL_API ClassB
{
public:
// conversion from ClassA (constructor):
ClassB(const ClassA& x) { Value = x.Value; }
int Value;
// conversion from ClassA (assignment):
//ClassB& operator= (const ClassA& x) { return *this; }
// conversion to ClassA (type-cast operator)
//operator ClassA() { return ClassA(); }
};
class DLL_API ClassC
{
public:
// This should NOT lead to a conversion
ClassC(const ClassA* x) { Value = x->Value; }
// This should lead to an explicit conversion
explicit ClassC(const ClassB& x) { Value = x.Value; }
int Value;
};

3
tests/CSharpTemp/CSharpTemp.cs

@ -63,6 +63,9 @@ namespace CppSharp.Tests
driver.Options.GeneratePropertiesAdvanced = true; driver.Options.GeneratePropertiesAdvanced = true;
driver.Options.GenerateVirtualTables = true; driver.Options.GenerateVirtualTables = true;
driver.Options.GenerateCopyConstructors = true; driver.Options.GenerateCopyConstructors = true;
// To ensure that calls to constructors in conversion operators
// are not ambiguous with multiple inheritance pass enabled.
driver.Options.GenerateConversionOperators = true;
driver.TranslationUnitPasses.AddPass(new TestAttributesPass()); driver.TranslationUnitPasses.AddPass(new TestAttributesPass());
} }

Loading…
Cancel
Save