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) @@ -2499,6 +2499,59 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
{
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())
{
case Stmt::BinaryOperatorClass:
@ -2514,11 +2567,11 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) @@ -2514,11 +2567,11 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
case Stmt::CXXStaticCastExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ExplicitCastExpr,
0,
WalkExpression(cast<CastExpr>(Expr)->getSubExpr()));
WalkExpressionEx(cast<CastExpr>(Expr)->getSubExpr()));
case Stmt::ImplicitCastExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ImplicitCastExpr,
0,
WalkExpression(cast<CastExpr>(Expr)->getSubExpr()));
WalkExpressionEx(cast<CastExpr>(Expr)->getSubExpr()));
case Stmt::CXXOperatorCallExprClass:
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXOperatorCallExpr,
WalkDeclaration(cast<CXXOperatorCallExpr>(Expr)->getCalleeDecl()));
@ -2530,13 +2583,13 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) @@ -2530,13 +2583,13 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
{
if (ConstructorExpr->isElidable())
{
return WalkExpression(ConstructorExpr->getArg(0));
return WalkExpressionEx(ConstructorExpr->getArg(0));
}
else
{
return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass,
WalkDeclaration(ConstructorExpr->getConstructor()),
WalkExpression(ConstructorExpr->getArg(0)));
WalkExpressionEx(ConstructorExpr->getArg(0)));
}
}
else
@ -2546,7 +2599,7 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) @@ -2546,7 +2599,7 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr)
}
}
case Stmt::MaterializeTemporaryExprClass:
return WalkExpression(cast<MaterializeTemporaryExpr>(Expr)->GetTemporaryExpr());
return WalkExpressionEx(cast<MaterializeTemporaryExpr>(Expr)->GetTemporaryExpr());
default:
break;
}

1
src/CppParser/Parser.h

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

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

@ -2289,9 +2289,13 @@ namespace CppSharp.Generators.CSharp @@ -2289,9 +2289,13 @@ namespace CppSharp.Generators.CSharp
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);
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)
WriteLine("return new {0}(({2}){1});", method.ConversionType,
WriteLine("return new {0}(({2}) {1});", method.ConversionType,
method.Parameters[0].Name, @interface.Name);
else
WriteLine("return new {0}({1});", method.ConversionType,

25
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -71,18 +71,21 @@ namespace CppSharp.Passes @@ -71,18 +71,21 @@ namespace CppSharp.Passes
if (@operator.IsStatic)
@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)),
Modifier = PointerType.TypeModifier.LVReference
};
@operator.Parameters.Insert(0, new Parameter
{
Name = Generator.GeneratedIdentifier("op"),
QualifiedType = new QualifiedType(type),
Kind = ParameterKind.OperatorParameter
});
var type = new PointerType
{
QualifiedPointee = new QualifiedType(new TagType(@class)),
Modifier = PointerType.TypeModifier.LVReference
};
@operator.Parameters.Insert(0, new Parameter
{
Name = Generator.GeneratedIdentifier("op"),
QualifiedType = new QualifiedType(type),
Kind = ParameterKind.OperatorParameter
});
}
}
}
}

52
src/Generator/Passes/ConstructorToConversionOperatorPass.cs

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

117
src/Generator/Passes/HandleDefaultParamValuesPass.cs

@ -15,6 +15,7 @@ namespace CppSharp.Passes @@ -15,6 +15,7 @@ namespace CppSharp.Passes
private static readonly Regex regexFunctionParams = new Regex(@"\(?(.+)\)?", 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 regexCtor = new Regex(@"^(\w+)\s*\(\w*\)$", RegexOptions.Compiled);
public override bool VisitFunctionDecl(Function function)
{
@ -44,10 +45,7 @@ namespace CppSharp.Passes @@ -44,10 +45,7 @@ namespace CppSharp.Passes
if (CheckForEnumValue(parameter.DefaultArgument, desugared))
continue;
CheckForAnonExpression(desugared, parameter);
CheckForDefaultEmptyChar(parameter, desugared);
}
GenerateOverloads(function, overloadIndices);
@ -64,21 +62,6 @@ namespace CppSharp.Passes @@ -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)
{
if (desugared.IsPointer())
@ -93,30 +76,6 @@ namespace CppSharp.Passes @@ -93,30 +76,6 @@ namespace CppSharp.Passes
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
Type type;
desugared.IsPointerTo(out type);
@ -126,6 +85,8 @@ namespace CppSharp.Passes @@ -126,6 +85,8 @@ namespace CppSharp.Passes
if (!type.TryGetClass(out decl))
return false;
var ctor = arg.Declaration as Method;
TypeMap typeMap;
if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap))
{
@ -153,20 +114,11 @@ namespace CppSharp.Passes @@ -153,20 +114,11 @@ namespace CppSharp.Passes
Enumeration @enum;
if (typeInSignature.TryGetEnum(out @enum))
{
var argCast = (CastExpr)arg;
Expression literal = ((CtorExpr)argCast.SubExpression).SubExpression;
if (CheckForEnumValue(literal, desugared))
{
argCast.String = literal.String;
argCast.SubExpression.String = literal.String;
return true;
}
else
{
return false;
}
return false;
}
if (ctor == null || !ctor.IsConstructor)
return false;
if (mappedTo == "string" && ctor.Parameters.Count == 0)
{
arg.String = "\"\"";
@ -174,23 +126,24 @@ namespace CppSharp.Passes @@ -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();
CheckForDefaultConstruct(innerDesugared, innerArg);
if (innerDesugared.IsPointer() && innerArg.String == "0")
innerArg.String = "";
arg.String = string.Format("new {0}({1})", ctor.Name, innerArg.String);
}
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);
arg.String = string.Format("new {0}", arg.String);
if (ctor != null && ctor.Parameters.Count > 0 && ctor.Parameters[0].Type.IsAddress())
{
arg.String = arg.String.Replace("(0)", "()");
return decl.IsValueType ? true : (bool?) null;
}
}
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;
@ -198,16 +151,7 @@ namespace CppSharp.Passes @@ -198,16 +151,7 @@ namespace CppSharp.Passes
private static bool CheckForEnumValue(Expression arg, Type desugared)
{
// Handle a simple cast (between int and enum, for example)
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;
var enumItem = arg.Declaration as Enumeration.Item;
if (enumItem != null)
{
arg.String = string.Format("{0}{1}{2}.{3}",
@ -217,20 +161,25 @@ namespace CppSharp.Passes @@ -217,20 +161,25 @@ namespace CppSharp.Passes
: enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name);
return true;
}
// Handle cases like "Flags::Flag1 | Flags::Flag2"
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;
if (@params.Contains("::"))
arg.String = regexDoubleColon.Replace(@params, desugared + ".");
else
arg.String = regexName.Replace(@params, desugared + ".$1");
TranslateEnumExpression(arg, desugared, @params);
return true;
}
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)
{
if (parameter.DefaultArgument.String == "0" && Driver.Options.MarshalCharAsManagedChar &&

10
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -164,4 +164,14 @@ public class CSharpTempTests : GeneratorTestFixture @@ -164,4 +164,14 @@ public class CSharpTempTests : GeneratorTestFixture
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) @@ -277,6 +277,12 @@ QGenericArgument::QGenericArgument(const char *name)
MethodsWithDefaultValues::MethodsWithDefaultValues(Foo foo)
{
m_foo = foo;
}
MethodsWithDefaultValues::MethodsWithDefaultValues(int a)
{
m_foo.A = a;
}
void MethodsWithDefaultValues::defaultPointer(Foo *ptr)
@ -347,6 +353,11 @@ void MethodsWithDefaultValues::rotate4x4Matrix(float angle, float x, float y, fl @@ -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)
{
}

4
tests/CSharpTemp/CSharpTemp.h

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

Loading…
Cancel
Save