Browse Source

Merge pull request #397 from ddobrev/master

Fixed the regressions in the code for default args
pull/399/head
João Matos 11 years ago
parent
commit
443b81496e
  1. 63
      src/CppParser/Parser.cpp
  2. 1
      src/CppParser/Parser.h
  3. 8
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 25
      src/Generator/Passes/CheckOperatorsOverloads.cs
  5. 52
      src/Generator/Passes/ConstructorToConversionOperatorPass.cs
  6. 117
      src/Generator/Passes/HandleDefaultParamValuesPass.cs
  7. 10
      tests/CSharpTemp/CSharpTemp.Tests.cs
  8. 11
      tests/CSharpTemp/CSharpTemp.cpp
  9. 4
      tests/CSharpTemp/CSharpTemp.h

63
src/CppParser/Parser.cpp

@ -2499,6 +2499,59 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
{ {
using namespace clang; using namespace clang;
switch (Expr->getStmtClass())
{
case Stmt::BinaryOperatorClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::BinaryOperator);
case Stmt::DeclRefExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::DeclRefExprClass,
WalkDeclaration(cast<DeclRefExpr>(Expr)->getDecl()));
case Stmt::CStyleCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::CXXReinterpretCastExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::ImplicitCastExprClass:
return WalkExpression(cast<CastExpr>(Expr)->getSubExprAsWritten());
case Stmt::CXXOperatorCallExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXOperatorCallExpr,
WalkDeclaration(cast<CXXOperatorCallExpr>(Expr)->getCalleeDecl()));
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass:
{
auto ConstructorExpr = cast<CXXConstructExpr>(Expr);
if (ConstructorExpr->getNumArgs() == 1)
{
auto Arg = ConstructorExpr->getArg(0);
auto TemporaryExpr = dyn_cast<MaterializeTemporaryExpr>(Arg);
if (TemporaryExpr)
{
auto Cast = dyn_cast<CastExpr>(TemporaryExpr->GetTemporaryExpr());
if (Cast && Cast->getSubExprAsWritten()->getStmtClass() != Stmt::IntegerLiteralClass)
return WalkExpression(Cast->getSubExprAsWritten());
}
}
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass,
WalkDeclaration(ConstructorExpr->getConstructor()));
}
case Stmt::MaterializeTemporaryExprClass:
return WalkExpression(cast<MaterializeTemporaryExpr>(Expr)->GetTemporaryExpr());
default:
break;
}
llvm::APSInt integer;
if (Expr->getStmtClass() != Stmt::CharacterLiteralClass &&
Expr->getStmtClass() != Stmt::CXXBoolLiteralExprClass &&
Expr->EvaluateAsInt(integer, C->getASTContext()))
return new AST::Expression(integer.toString(10));
return new AST::Expression(GetStringFromStatement(Expr));
}
AST::Expression* Parser::WalkExpressionEx(clang::Expr* Expr)
{
using namespace clang;
switch (Expr->getStmtClass()) switch (Expr->getStmtClass())
{ {
case Stmt::BinaryOperatorClass: case Stmt::BinaryOperatorClass:
@ -2514,11 +2567,11 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
case Stmt::CXXStaticCastExprClass: case Stmt::CXXStaticCastExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ExplicitCastExpr, return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ExplicitCastExpr,
0, 0,
WalkExpression(cast<CastExpr>(Expr)->getSubExpr())); WalkExpressionEx(cast<CastExpr>(Expr)->getSubExpr()));
case Stmt::ImplicitCastExprClass: case Stmt::ImplicitCastExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ImplicitCastExpr, return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ImplicitCastExpr,
0, 0,
WalkExpression(cast<CastExpr>(Expr)->getSubExpr())); WalkExpressionEx(cast<CastExpr>(Expr)->getSubExpr()));
case Stmt::CXXOperatorCallExprClass: case Stmt::CXXOperatorCallExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXOperatorCallExpr, return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXOperatorCallExpr,
WalkDeclaration(cast<CXXOperatorCallExpr>(Expr)->getCalleeDecl())); WalkDeclaration(cast<CXXOperatorCallExpr>(Expr)->getCalleeDecl()));
@ -2530,13 +2583,13 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
{ {
if (ConstructorExpr->isElidable()) if (ConstructorExpr->isElidable())
{ {
return WalkExpression(ConstructorExpr->getArg(0)); return WalkExpressionEx(ConstructorExpr->getArg(0));
} }
else else
{ {
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass,
WalkDeclaration(ConstructorExpr->getConstructor()), WalkDeclaration(ConstructorExpr->getConstructor()),
WalkExpression(ConstructorExpr->getArg(0))); WalkExpressionEx(ConstructorExpr->getArg(0)));
} }
} }
else else
@ -2546,7 +2599,7 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
} }
} }
case Stmt::MaterializeTemporaryExprClass: case Stmt::MaterializeTemporaryExprClass:
return WalkExpression(cast<MaterializeTemporaryExpr>(Expr)->GetTemporaryExpr()); return WalkExpressionEx(cast<MaterializeTemporaryExpr>(Expr)->GetTemporaryExpr());
default: default:
break; break;
} }

1
src/CppParser/Parser.h

@ -98,6 +98,7 @@ protected:
PreprocessedEntity* WalkPreprocessedEntity(Declaration* Decl, PreprocessedEntity* WalkPreprocessedEntity(Declaration* Decl,
clang::PreprocessedEntity* PPEntity); clang::PreprocessedEntity* PPEntity);
AST::Expression* WalkExpression(clang::Expr* Expression); AST::Expression* WalkExpression(clang::Expr* Expression);
AST::Expression* WalkExpressionEx(clang::Expr* Expression);
std::string GetStringFromStatement(const clang::Stmt* Statement); std::string GetStringFromStatement(const clang::Stmt* Statement);
// Clang helpers // Clang helpers

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

@ -2289,9 +2289,13 @@ namespace CppSharp.Generators.CSharp
if (method.Kind == CXXMethodKind.Conversion) if (method.Kind == CXXMethodKind.Conversion)
{ {
// To avoid ambiguity when having the multiple inheritance pass enabled // To avoid ambiguity when having the multiple inheritance pass enabled
var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class); var paramType = method.Parameters[0].Type.SkipPointerRefs().Desugar();
Class paramClass;
Class @interface = null;
if (paramType.TryGetClass(out paramClass))
@interface = paramClass.Namespace.Classes.Find(c => c.OriginalClass == paramClass);
if (@interface != null) if (@interface != null)
WriteLine("return new {0}(({2}){1});", method.ConversionType, WriteLine("return new {0}(({2}) {1});", method.ConversionType,
method.Parameters[0].Name, @interface.Name); method.Parameters[0].Name, @interface.Name);
else else
WriteLine("return new {0}({1});", method.ConversionType, WriteLine("return new {0}({1});", method.ConversionType,

25
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -71,18 +71,21 @@ namespace CppSharp.Passes
if (@operator.IsStatic) if (@operator.IsStatic)
@operator.Parameters = @operator.Parameters.Skip(1).ToList(); @operator.Parameters = @operator.Parameters.Skip(1).ToList();
var type = new PointerType if (@operator.ConversionType.Type == null || @operator.Parameters.Count == 0)
{ {
QualifiedPointee = new QualifiedType(new TagType(@class)), var type = new PointerType
Modifier = PointerType.TypeModifier.LVReference {
}; QualifiedPointee = new QualifiedType(new TagType(@class)),
Modifier = PointerType.TypeModifier.LVReference
@operator.Parameters.Insert(0, new Parameter };
{
Name = Generator.GeneratedIdentifier("op"), @operator.Parameters.Insert(0, new Parameter
QualifiedType = new QualifiedType(type), {
Kind = ParameterKind.OperatorParameter Name = Generator.GeneratedIdentifier("op"),
}); QualifiedType = new QualifiedType(type),
Kind = ParameterKind.OperatorParameter
});
}
} }
} }
} }

52
src/Generator/Passes/ConstructorToConversionOperatorPass.cs

@ -1,5 +1,4 @@
using System.Linq; using CppSharp.AST;
using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
namespace CppSharp.Passes namespace CppSharp.Passes
@ -19,38 +18,45 @@ namespace CppSharp.Passes
if (method.Parameters.Count != 1) if (method.Parameters.Count != 1)
return false; return false;
var parameter = method.Parameters[0]; var parameter = method.Parameters[0];
var parameterType = parameter.Type as PointerType; // TODO: disable implicit operators for C++/CLI because they seem not to be support parameters
if (parameterType == null) if (!Driver.Options.IsCSharpGenerator)
return false; {
if (!parameterType.IsReference) var pointerType = parameter.Type as PointerType;
return false; if (pointerType != null && !pointerType.IsReference)
var qualifiedPointee = parameterType.QualifiedPointee; return false;
}
var qualifiedPointee = parameter.Type.SkipPointerRefs();
Class castFromClass; Class castFromClass;
if (!qualifiedPointee.Type.TryGetClass(out castFromClass)) if (qualifiedPointee.TryGetClass(out castFromClass))
return false; {
var castToClass = method.OriginalNamespace as Class; var castToClass = method.OriginalNamespace as Class;
if (castToClass == null) if (castToClass == null)
return false; return false;
if (castFromClass == castToClass) if (castFromClass == castToClass)
return false; return false;
}
var operatorKind = method.IsExplicit var operatorKind = method.IsExplicit
? CXXOperatorKind.ExplicitConversion ? CXXOperatorKind.ExplicitConversion
: CXXOperatorKind.Conversion; : CXXOperatorKind.Conversion;
var castToType = new TagType(castToClass); var qualifiedCastToType = new QualifiedType(new TagType(method.Namespace));
var qualifiedCastToType = new QualifiedType(castToType); var conversionOperator = new Method
var conversionOperator = new Method()
{ {
Name = Operators.GetOperatorIdentifier(operatorKind), Name = Operators.GetOperatorIdentifier(operatorKind),
Namespace = castFromClass, Namespace = method.Namespace,
Kind = CXXMethodKind.Conversion, Kind = CXXMethodKind.Conversion,
SynthKind = FunctionSynthKind.ComplementOperator, SynthKind = FunctionSynthKind.ComplementOperator,
ConversionType = qualifiedCastToType, ConversionType = qualifiedCastToType,
ReturnType = qualifiedCastToType ReturnType = qualifiedCastToType,
OperatorKind = operatorKind
}; };
conversionOperator.OperatorKind = operatorKind; var p = new Parameter(parameter);
Class @class;
castFromClass.Methods.Add(conversionOperator); if (p.Type.SkipPointerRefs().TryGetClass(out @class))
p.QualifiedType = new QualifiedType(new TagType(@class), parameter.QualifiedType.Qualifiers);
p.DefaultArgument = null;
conversionOperator.Parameters.Add(p);
((Class) method.Namespace).Methods.Add(conversionOperator);
return true; return true;
} }
} }

117
src/Generator/Passes/HandleDefaultParamValuesPass.cs

@ -15,6 +15,7 @@ namespace CppSharp.Passes
private static readonly Regex regexFunctionParams = new Regex(@"\(?(.+)\)?", RegexOptions.Compiled); private static readonly Regex regexFunctionParams = new Regex(@"\(?(.+)\)?", RegexOptions.Compiled);
private static readonly Regex regexDoubleColon = new Regex(@"\w+::", RegexOptions.Compiled); private static readonly Regex regexDoubleColon = new Regex(@"\w+::", RegexOptions.Compiled);
private static readonly Regex regexName = new Regex(@"(\w+)", RegexOptions.Compiled); private static readonly Regex regexName = new Regex(@"(\w+)", RegexOptions.Compiled);
private static readonly Regex regexCtor = new Regex(@"^(\w+)\s*\(\w*\)$", RegexOptions.Compiled);
public override bool VisitFunctionDecl(Function function) public override bool VisitFunctionDecl(Function function)
{ {
@ -44,10 +45,7 @@ namespace CppSharp.Passes
if (CheckForEnumValue(parameter.DefaultArgument, desugared)) if (CheckForEnumValue(parameter.DefaultArgument, desugared))
continue; continue;
CheckForAnonExpression(desugared, parameter);
CheckForDefaultEmptyChar(parameter, desugared); CheckForDefaultEmptyChar(parameter, desugared);
} }
GenerateOverloads(function, overloadIndices); GenerateOverloads(function, overloadIndices);
@ -64,21 +62,6 @@ namespace CppSharp.Passes
} }
} }
private bool CheckForAnonExpression(Type desugared, Parameter parameter)
{
var cast = parameter.DefaultArgument as CastExpr;
if (cast != null)
{
if (cast.SubExpression is BuiltinTypeExpression)
{
// The output string is correct in the deepest expression. Copy it to the outernmost.
cast.String = cast.SubExpression.String;
return true;
}
}
return true;
}
private static bool CheckForDefaultPointer(Type desugared, Parameter parameter) private static bool CheckForDefaultPointer(Type desugared, Parameter parameter)
{ {
if (desugared.IsPointer()) if (desugared.IsPointer())
@ -93,30 +76,6 @@ namespace CppSharp.Passes
private bool? CheckForDefaultConstruct(Type desugared, Expression arg) private bool? CheckForDefaultConstruct(Type desugared, Expression arg)
{ {
// Unwrapping the constructor and a possible cast
Method ctor = null;
CastExpr castExpression = null;
CtorExpr ctorExpression = null;
if (arg is CtorExpr)
{
ctorExpression = (CtorExpr)arg;
ctor = (Method)ctorExpression.Declaration;
}
else if (arg is CastExpr && ((CastExpr)arg).SubExpression is CtorExpr)
{
castExpression = (CastExpr)arg;
ctorExpression = (CtorExpr)castExpression.SubExpression;
ctor = (Method)ctorExpression.Declaration;
}
else
{
return false;
}
var innerArg = ctorExpression.SubExpression;
if (ctor == null || !ctor.IsConstructor)
return false;
// Unwrapping the underlying type behind a possible pointer/reference // Unwrapping the underlying type behind a possible pointer/reference
Type type; Type type;
desugared.IsPointerTo(out type); desugared.IsPointerTo(out type);
@ -126,6 +85,8 @@ namespace CppSharp.Passes
if (!type.TryGetClass(out decl)) if (!type.TryGetClass(out decl))
return false; return false;
var ctor = arg.Declaration as Method;
TypeMap typeMap; TypeMap typeMap;
if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap)) if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap))
{ {
@ -153,20 +114,11 @@ namespace CppSharp.Passes
Enumeration @enum; Enumeration @enum;
if (typeInSignature.TryGetEnum(out @enum)) if (typeInSignature.TryGetEnum(out @enum))
{ {
var argCast = (CastExpr)arg; return false;
Expression literal = ((CtorExpr)argCast.SubExpression).SubExpression;
if (CheckForEnumValue(literal, desugared))
{
argCast.String = literal.String;
argCast.SubExpression.String = literal.String;
return true;
}
else
{
return false;
}
} }
if (ctor == null || !ctor.IsConstructor)
return false;
if (mappedTo == "string" && ctor.Parameters.Count == 0) if (mappedTo == "string" && ctor.Parameters.Count == 0)
{ {
arg.String = "\"\""; arg.String = "\"\"";
@ -174,23 +126,24 @@ namespace CppSharp.Passes
} }
} }
if (innerArg is CtorExpr || innerArg is CastExpr) if (regexCtor.IsMatch(arg.String))
{ {
Type innerDesugared = ctor.Parameters[0].Type.Desugar(); arg.String = string.Format("new {0}", arg.String);
CheckForDefaultConstruct(innerDesugared, innerArg); if (ctor != null && ctor.Parameters.Count > 0 && ctor.Parameters[0].Type.IsAddress())
if (innerDesugared.IsPointer() && innerArg.String == "0") {
innerArg.String = ""; arg.String = arg.String.Replace("(0)", "()");
arg.String = string.Format("new {0}({1})", ctor.Name, innerArg.String); return decl.IsValueType ? true : (bool?) null;
} }
else if (innerArg != null)
{
Type innerDesugared = ctor.Parameters[0].Type.Desugar();
CheckForEnumValue(innerArg, innerDesugared);
arg.String = string.Format("new {0}({1})", ctor.Name, innerArg.String);
} }
else else
{ {
arg.String = string.Format("new {0}()", ctor.Name); if (ctor != null && ctor.Parameters.Count > 0)
{
var finalPointee = ctor.Parameters[0].Type.SkipPointerRefs().Desugar();
Enumeration @enum;
if (finalPointee.TryGetEnum(out @enum))
TranslateEnumExpression(arg, finalPointee, arg.String);
}
} }
return decl.IsValueType ? true : (bool?) null; return decl.IsValueType ? true : (bool?) null;
@ -198,16 +151,7 @@ namespace CppSharp.Passes
private static bool CheckForEnumValue(Expression arg, Type desugared) private static bool CheckForEnumValue(Expression arg, Type desugared)
{ {
// Handle a simple cast (between int and enum, for example) var enumItem = arg.Declaration as Enumeration.Item;
var argCast = arg as CastExpr;
Expression literal;
if (argCast != null)
literal = argCast.SubExpression;
else
literal = arg;
// The default case
var enumItem = literal.Declaration as Enumeration.Item;
if (enumItem != null) if (enumItem != null)
{ {
arg.String = string.Format("{0}{1}{2}.{3}", arg.String = string.Format("{0}{1}{2}.{3}",
@ -217,20 +161,25 @@ namespace CppSharp.Passes
: enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name); : enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name);
return true; return true;
} }
// Handle cases like "Flags::Flag1 | Flags::Flag2"
var call = arg.Declaration as Function; var call = arg.Declaration as Function;
if ((call != null && call.ReturnType.Type.IsEnum()) || arg.Class == StatementClass.BinaryOperator) if ((call != null || arg.Class == StatementClass.BinaryOperator) && arg.String != "0")
{ {
string @params = regexFunctionParams.Match(arg.String).Groups[1].Value; string @params = regexFunctionParams.Match(arg.String).Groups[1].Value;
if (@params.Contains("::")) TranslateEnumExpression(arg, desugared, @params);
arg.String = regexDoubleColon.Replace(@params, desugared + ".");
else
arg.String = regexName.Replace(@params, desugared + ".$1");
return true; return true;
} }
return false; return false;
} }
private static void TranslateEnumExpression(Expression arg, Type desugared, string @params)
{
if (@params.Contains("::"))
arg.String = regexDoubleColon.Replace(@params, desugared + ".");
else
arg.String = regexName.Replace(@params, desugared + ".$1");
}
private void CheckForDefaultEmptyChar(Parameter parameter, Type desugared) private void CheckForDefaultEmptyChar(Parameter parameter, Type desugared)
{ {
if (parameter.DefaultArgument.String == "0" && Driver.Options.MarshalCharAsManagedChar && if (parameter.DefaultArgument.String == "0" && Driver.Options.MarshalCharAsManagedChar &&

10
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -164,4 +164,14 @@ public class CSharpTempTests : GeneratorTestFixture
Assert.AreEqual(q1.Array[i], q2.Array[i]); Assert.AreEqual(q1.Array[i], q2.Array[i]);
} }
} }
[Test]
public void TestImplicitCtor()
{
Foo foo = new Foo { A = 10 };
MethodsWithDefaultValues m = foo;
Assert.AreEqual(foo.A, m.A);
MethodsWithDefaultValues m1 = 5;
Assert.AreEqual(5, m1.A);
}
} }

11
tests/CSharpTemp/CSharpTemp.cpp

@ -277,6 +277,12 @@ QGenericArgument::QGenericArgument(const char *name)
MethodsWithDefaultValues::MethodsWithDefaultValues(Foo foo) MethodsWithDefaultValues::MethodsWithDefaultValues(Foo foo)
{ {
m_foo = foo;
}
MethodsWithDefaultValues::MethodsWithDefaultValues(int a)
{
m_foo.A = a;
} }
void MethodsWithDefaultValues::defaultPointer(Foo *ptr) void MethodsWithDefaultValues::defaultPointer(Foo *ptr)
@ -347,6 +353,11 @@ void MethodsWithDefaultValues::rotate4x4Matrix(float angle, float x, float y, fl
{ {
} }
int MethodsWithDefaultValues::getA()
{
return m_foo.A;
}
void HasPrivateOverrideBase::privateOverride(int i) void HasPrivateOverrideBase::privateOverride(int i)
{ {
} }

4
tests/CSharpTemp/CSharpTemp.h

@ -248,6 +248,7 @@ class DLL_API MethodsWithDefaultValues
{ {
public: public:
MethodsWithDefaultValues(Foo foo = Foo()); MethodsWithDefaultValues(Foo foo = Foo());
MethodsWithDefaultValues(int a);
void defaultPointer(Foo* ptr = 0); void defaultPointer(Foo* ptr = 0);
void defaultVoidStar(void* ptr = 0); void defaultVoidStar(void* ptr = 0);
void defaultValueType(QGenericArgument valueType = QGenericArgument()); void defaultValueType(QGenericArgument valueType = QGenericArgument());
@ -270,6 +271,9 @@ public:
void defaultIntWithLongExpression(unsigned int i = DEFAULT_INT); void defaultIntWithLongExpression(unsigned int i = DEFAULT_INT);
void defaultRefTypeEnumImplicitCtor(const QColor &fillColor = Qt::white); void defaultRefTypeEnumImplicitCtor(const QColor &fillColor = Qt::white);
void rotate4x4Matrix(float angle, float x, float y, float z = 0.0f); void rotate4x4Matrix(float angle, float x, float y, float z = 0.0f);
int getA();
private:
Foo m_foo;
}; };
class DLL_API HasPrivateOverrideBase class DLL_API HasPrivateOverrideBase

Loading…
Cancel
Save