diff --git a/src/AST/Expression.cs b/src/AST/Expression.cs index 03b5547b..9625da35 100644 --- a/src/AST/Expression.cs +++ b/src/AST/Expression.cs @@ -36,12 +36,31 @@ namespace CppSharp.AST public override T Visit(IExpressionVisitor visitor) { - return visitor.VisitBuiltinExpression(this); + return visitor.VisitExpression(this); + } + } + + public class CastExpr : Expression + { + public Expression SubExpression; + + public override T Visit(IExpressionVisitor visitor) + { + return visitor.VisitExpression(this); + } + } + public class CtorExpr : Expression + { + public Expression SubExpression; + + public override T Visit(IExpressionVisitor visitor) + { + return visitor.VisitExpression(this); } } public interface IExpressionVisitor { - T VisitBuiltinExpression(BuiltinTypeExpression builtinType); + T VisitExpression(Expression exp); } } \ No newline at end of file diff --git a/src/AST/Statement.cs b/src/AST/Statement.cs index 3f8e1a68..712acb5d 100644 --- a/src/AST/Statement.cs +++ b/src/AST/Statement.cs @@ -6,7 +6,9 @@ BinaryOperator, DeclarationReference, ConstructorReference, - CXXOperatorCall + CXXOperatorCall, + ImplicitCast, + ExplicitCast, } public abstract class Statement diff --git a/src/Core/Parser/ASTConverter.cs b/src/Core/Parser/ASTConverter.cs index 99e8f0ee..1da4b260 100644 --- a/src/Core/Parser/ASTConverter.cs +++ b/src/Core/Parser/ASTConverter.cs @@ -847,24 +847,51 @@ namespace CppSharp if (statement == null) return null; - var expression = new AST.BuiltinTypeExpression(); - expression.Declaration = this.typeConverter.declConverter.Visit(statement.Decl); - expression.String = statement.String; + AST.Expression expression; switch (statement.Class) { case StatementClass.BinaryOperator: + expression = new AST.BuiltinTypeExpression(); expression.Class = AST.StatementClass.BinaryOperator; break; case StatementClass.DeclRefExprClass: + expression = new AST.BuiltinTypeExpression(); expression.Class = AST.StatementClass.DeclarationReference; break; - case StatementClass.CXXConstructExprClass: - expression.Class = AST.StatementClass.ConstructorReference; - break; case StatementClass.CXXOperatorCallExpr: + expression = new AST.BuiltinTypeExpression(); expression.Class = AST.StatementClass.CXXOperatorCall; break; + case StatementClass.CXXConstructExprClass: + { + var ctorExp = new AST.CtorExpr(); + ctorExp.SubExpression = VisitStatement(((Expression)statement).Subexpression); + expression = ctorExp; + expression.Class = AST.StatementClass.ConstructorReference; + break; + } + case StatementClass.ImplicitCastExpr: + { + var castExp = new AST.CastExpr(); + castExp.SubExpression = VisitStatement(((Expression)statement).Subexpression); + expression = castExp; + expression.Class = AST.StatementClass.ImplicitCast; + break; + } + case StatementClass.ExplicitCastExpr: + { + var castExp = new AST.CastExpr(); + castExp.SubExpression = VisitStatement(((Expression)statement).Subexpression); + expression = castExp; + expression.Class = AST.StatementClass.ExplicitCast; + break; + } + default: + expression = new AST.BuiltinTypeExpression(); + break; } + expression.Declaration = this.typeConverter.declConverter.Visit(statement.Decl); + expression.String = statement.String; return expression; } diff --git a/src/CppParser/AST.cpp b/src/CppParser/AST.cpp index 0154bdb8..fa2b6372 100644 --- a/src/CppParser/AST.cpp +++ b/src/CppParser/AST.cpp @@ -433,7 +433,8 @@ DEF_STRING(Statement, String) Statement::Statement(const std::string& str, StatementClass stmtClass, Declaration* decl) : String(str), Class(stmtClass), Decl(decl) {} -Expression::Expression(const std::string& str, StatementClass stmtClass, Declaration* decl) : Statement(str, stmtClass, decl) {} +Expression::Expression(const std::string& str, StatementClass stmtClass, Declaration* decl, Expression* subexpr) +:Statement(str, stmtClass, decl), Subexpression(subexpr) {} Parameter::Parameter() : Declaration(DeclarationKind::Parameter), IsIndirect(false), HasDefaultValue(false), DefaultArgument(0) {} diff --git a/src/CppParser/AST.h b/src/CppParser/AST.h index 0fe1e901..f983be80 100644 --- a/src/CppParser/AST.h +++ b/src/CppParser/AST.h @@ -465,7 +465,9 @@ enum class StatementClass BinaryOperator, DeclRefExprClass, CXXConstructExprClass, - CXXOperatorCallExpr + CXXOperatorCallExpr, + ImplicitCastExpr, + ExplicitCastExpr, }; class CS_API Statement @@ -480,7 +482,8 @@ public: class CS_API Expression : public Statement { public: - Expression(const std::string& str, StatementClass Class = StatementClass::Any, Declaration* decl = 0); + Expression(const std::string& str, StatementClass Class = StatementClass::Any, Declaration* decl = 0, Expression* subexpr = 0); + Expression* Subexpression; }; class CS_API Parameter : public Declaration diff --git a/src/CppParser/Bindings/CLI/AST.cpp b/src/CppParser/Bindings/CLI/AST.cpp index 490401c0..3f863fc2 100644 --- a/src/CppParser/Bindings/CLI/AST.cpp +++ b/src/CppParser/Bindings/CLI/AST.cpp @@ -1562,6 +1562,16 @@ CppSharp::Parser::AST::Expression^ CppSharp::Parser::AST::Expression::__CreateIn return gcnew CppSharp::Parser::AST::Expression((::CppSharp::CppParser::AST::Expression*) native.ToPointer()); } +CppSharp::Parser::AST::Expression^ CppSharp::Parser::AST::Expression::Subexpression::get() +{ + return (((::CppSharp::CppParser::AST::Expression*)NativePtr)->Subexpression == nullptr) ? nullptr : gcnew CppSharp::Parser::AST::Expression((::CppSharp::CppParser::AST::Expression*)((::CppSharp::CppParser::AST::Expression*)NativePtr)->Subexpression); +} + +void CppSharp::Parser::AST::Expression::Subexpression::set(CppSharp::Parser::AST::Expression^ value) +{ + ((::CppSharp::CppParser::AST::Expression*)NativePtr)->Subexpression = (::CppSharp::CppParser::AST::Expression*)value->NativePtr; +} + CppSharp::Parser::AST::Parameter::Parameter(::CppSharp::CppParser::AST::Parameter* native) : CppSharp::Parser::AST::Declaration((::CppSharp::CppParser::AST::Declaration*)native) { diff --git a/src/CppParser/Bindings/CLI/AST.h b/src/CppParser/Bindings/CLI/AST.h index 5d4b243b..b6e2b0be 100644 --- a/src/CppParser/Bindings/CLI/AST.h +++ b/src/CppParser/Bindings/CLI/AST.h @@ -214,7 +214,9 @@ namespace CppSharp BinaryOperator = 1, DeclRefExprClass = 2, CXXConstructExprClass = 3, - CXXOperatorCallExpr = 4 + CXXOperatorCallExpr = 4, + ImplicitCastExpr = 5, + ExplicitCastExpr = 6 }; public enum struct TemplateSpecializationKind @@ -1211,6 +1213,11 @@ namespace CppSharp Expression(::CppSharp::CppParser::AST::Expression* native); static Expression^ __CreateInstance(::System::IntPtr native); + property CppSharp::Parser::AST::Expression^ Subexpression + { + CppSharp::Parser::AST::Expression^ get(); + void set(CppSharp::Parser::AST::Expression^); + } }; public ref class Parameter : CppSharp::Parser::AST::Declaration diff --git a/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/AST.cs b/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/AST.cs index db3b4f0e..4e29cbaa 100644 --- a/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/AST.cs +++ b/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/AST.cs @@ -137,7 +137,9 @@ namespace CppSharp BinaryOperator = 1, DeclRefExprClass = 2, CXXConstructExprClass = 3, - CXXOperatorCallExpr = 4 + CXXOperatorCallExpr = 4, + ImplicitCastExpr = 5, + ExplicitCastExpr = 6 } public enum TemplateSpecializationKind @@ -4170,7 +4172,7 @@ namespace CppSharp public unsafe partial class Expression : CppSharp.Parser.AST.Statement, IDisposable { - [StructLayout(LayoutKind.Explicit, Size = 32)] + [StructLayout(LayoutKind.Explicit, Size = 36)] public new partial struct Internal { [FieldOffset(0)] @@ -4179,6 +4181,9 @@ namespace CppSharp [FieldOffset(4)] public global::System.IntPtr Decl; + [FieldOffset(32)] + public global::System.IntPtr Subexpression; + [SuppressUnmanagedCodeSecurity] [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, EntryPoint="??0Expression@AST@CppParser@CppSharp@@QAE@ABV0123@@Z")] @@ -4204,7 +4209,7 @@ namespace CppSharp private static Expression.Internal* __CopyValue(Expression.Internal native) { - var ret = Marshal.AllocHGlobal(32); + var ret = Marshal.AllocHGlobal(36); CppSharp.Parser.AST.Expression.Internal.cctor_1(ret, new global::System.IntPtr(&native)); return (Expression.Internal*) ret; } @@ -4228,6 +4233,21 @@ namespace CppSharp } base.Dispose(disposing); } + + public CppSharp.Parser.AST.Expression Subexpression + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return (__ptr->Subexpression == IntPtr.Zero) ? null : CppSharp.Parser.AST.Expression.__CreateInstance(__ptr->Subexpression); + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->Subexpression = value == (CppSharp.Parser.AST.Expression) null ? global::System.IntPtr.Zero : value.__Instance; + } + } } public unsafe partial class Parameter : CppSharp.Parser.AST.Declaration, IDisposable diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index ce727d7d..faa510f0 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -2510,8 +2510,13 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) case Stmt::CXXFunctionalCastExprClass: case Stmt::CXXReinterpretCastExprClass: case Stmt::CXXStaticCastExprClass: + return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ExplicitCastExpr, + 0, + WalkExpression(cast(Expr)->getSubExpr())); case Stmt::ImplicitCastExprClass: - return WalkExpression(cast(Expr)->getSubExprAsWritten()); + return new AST::Expression(GetStringFromStatement(Expr), StatementClass::ImplicitCastExpr, + 0, + WalkExpression(cast(Expr)->getSubExpr())); case Stmt::CXXOperatorCallExprClass: return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXOperatorCallExpr, WalkDeclaration(cast(Expr)->getCalleeDecl())); @@ -2521,17 +2526,22 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) auto ConstructorExpr = cast(Expr); if (ConstructorExpr->getNumArgs() == 1) { - auto Arg = ConstructorExpr->getArg(0); - auto TemporaryExpr = dyn_cast(Arg); - if (TemporaryExpr) + if (ConstructorExpr->isElidable()) { - auto Cast = dyn_cast(TemporaryExpr->GetTemporaryExpr()); - if (Cast && Cast->getSubExprAsWritten()->getStmtClass() != Stmt::IntegerLiteralClass) - return WalkExpression(Cast->getSubExprAsWritten()); + return WalkExpression(ConstructorExpr->getArg(0)); } + else + { + return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, + WalkDeclaration(ConstructorExpr->getConstructor()), + WalkExpression(ConstructorExpr->getArg(0))); + } + } + else + { + return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, + WalkDeclaration(ConstructorExpr->getConstructor())); } - return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, - WalkDeclaration(ConstructorExpr->getConstructor())); } case Stmt::MaterializeTemporaryExprClass: return WalkExpression(cast(Expr)->GetTemporaryExpr()); diff --git a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs index 9b450e60..84a450ff 100644 --- a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs @@ -15,8 +15,7 @@ namespace CppSharp.Generators.CSharp public static class CSharpExpressionPrinterExtensions { - public static CSharpExpressionPrinterResult CSharpValue(this Expression value, - CSharpExpressionPrinter printer) + public static CSharpExpressionPrinterResult CSharpValue(this Expression value, CSharpExpressionPrinter printer) { return value.Visit(printer); } @@ -25,11 +24,11 @@ namespace CppSharp.Generators.CSharp public class CSharpExpressionPrinter : IExpressionPrinter, IExpressionVisitor { - public CSharpExpressionPrinterResult VisitBuiltinExpression(BuiltinTypeExpression builtinType) + public CSharpExpressionPrinterResult VisitExpression(Expression expr) { return new CSharpExpressionPrinterResult() { - Value = builtinType.ToString(), + Value = expr.ToString(), }; } diff --git a/src/Generator/Passes/HandleDefaultParamValuesPass.cs b/src/Generator/Passes/HandleDefaultParamValuesPass.cs index 685007b0..092da9d6 100644 --- a/src/Generator/Passes/HandleDefaultParamValuesPass.cs +++ b/src/Generator/Passes/HandleDefaultParamValuesPass.cs @@ -28,7 +28,7 @@ namespace CppSharp.Passes if (CheckForDefaultPointer(desugared, parameter)) continue; - bool? defaultConstruct = CheckForDefaultConstruct(desugared, parameter); + bool? defaultConstruct = CheckForDefaultConstruct(desugared, parameter.DefaultArgument); if (defaultConstruct == null || (!Driver.Options.MarshalCharAsManagedChar && parameter.Type.Desugar().IsPrimitiveType(PrimitiveType.UChar))) @@ -39,10 +39,13 @@ namespace CppSharp.Passes if (defaultConstruct == true) continue; - if (CheckForEnumValue(parameter, desugared)) + if (CheckForEnumValue(parameter.DefaultArgument, desugared)) continue; + CheckForAnonExpression(desugared, parameter); + CheckForDefaultEmptyChar(parameter, desugared); + } GenerateOverloads(function, overloadIndices); @@ -50,6 +53,21 @@ namespace CppSharp.Passes return result; } + 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()) @@ -62,20 +80,42 @@ namespace CppSharp.Passes return false; } - private bool? CheckForDefaultConstruct(Type desugared, Parameter parameter) + private bool? CheckForDefaultConstruct(Type desugared, Expression arg) { - Method ctor = parameter.DefaultArgument.Declaration as Method; + // 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); type = type ?? desugared; + Class decl; if (!type.TryGetClass(out decl)) return false; - TypeMap typeMap; + TypeMap typeMap; if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap)) { Type typeInSignature; @@ -102,43 +142,79 @@ namespace CppSharp.Passes Enumeration @enum; if (typeInSignature.TryGetEnum(out @enum)) { - return true; + 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; + } } if (mappedTo == "string" && ctor.Parameters.Count == 0) { - parameter.DefaultArgument.String = "\"\""; + arg.String = "\"\""; return true; } } - parameter.DefaultArgument.String = string.Format("new {0}", parameter.DefaultArgument.String); - if (ctor.Parameters.Count > 0 && ctor.Parameters[0].OriginalName == "_0") - parameter.DefaultArgument.String = parameter.DefaultArgument.String.Replace("(0)", "()"); + if (innerArg is CtorExpr || innerArg is CastExpr) + { + 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); + } + else + { + arg.String = string.Format("new {0}()", ctor.Name); + } return decl.IsValueType ? true : (bool?) null; } - private static bool CheckForEnumValue(Parameter parameter, Type desugared) + private static bool CheckForEnumValue(Expression arg, Type desugared) { - var enumItem = parameter.DefaultArgument.Declaration as Enumeration.Item; + // 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; if (enumItem != null) { - parameter.DefaultArgument.String = string.Format("{0}{1}{2}.{3}", + arg.String = string.Format("{0}{1}{2}.{3}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, string.IsNullOrEmpty(enumItem.Namespace.Namespace.Name) ? string.Empty : enumItem.Namespace.Namespace.Name + ".", enumItem.Namespace.Name, enumItem.Name); return true; } - - var call = parameter.DefaultArgument.Declaration as Function; - if (call != null || parameter.DefaultArgument.Class == StatementClass.BinaryOperator) + // Handle cases like "Flags::Flag1 | Flags::Flag2" + var call = arg.Declaration as Function; + if ((call != null && call.ReturnType.Type.IsEnum()) || arg.Class == StatementClass.BinaryOperator) { - string @params = regexFunctionParams.Match(parameter.DefaultArgument.String).Groups[1].Value; + string @params = regexFunctionParams.Match(arg.String).Groups[1].Value; if (@params.Contains("::")) - parameter.DefaultArgument.String = regexDoubleColon.Replace(@params, desugared + "."); + arg.String = regexDoubleColon.Replace(@params, desugared + "."); else - parameter.DefaultArgument.String = regexName.Replace(@params, desugared + ".$1"); + arg.String = regexName.Replace(@params, desugared + ".$1"); return true; } return false; diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp index 09348260..4afe726e 100644 --- a/tests/CSharpTemp/CSharpTemp.cpp +++ b/tests/CSharpTemp/CSharpTemp.cpp @@ -31,6 +31,39 @@ const Foo& Bar::operator[](int i) const return m_foo; } + +Quux::Quux() +{ + +} + +Quux::Quux(int i) +{ + +} + +Quux::Quux(char c) +{ + +} + +Quux::Quux(Foo f) +{ + +} + + + +QColor::QColor() +{ + +} + +QColor::QColor(Qt::GlobalColor color) +{ + +} + Qux::Qux() { @@ -294,10 +327,22 @@ void MethodsWithDefaultValues::defaultMappedToZeroEnum(QFlags qFlags) { } +void MethodsWithDefaultValues::defaultImplicitCtorInt(Quux arg) +{ +} + +void MethodsWithDefaultValues::defaultImplicitCtorChar(Quux arg) +{ +} + void MethodsWithDefaultValues::defaultIntWithLongExpression(unsigned int i) { } +void MethodsWithDefaultValues::defaultRefTypeEnumImplicitCtor(const QColor &fillColor) +{ +} + void HasPrivateOverrideBase::privateOverride(int i) { } diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index dfa2a679..d5a76e39 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -16,6 +16,18 @@ protected: int P; }; +class DLL_API Quux +{ +public: + Quux(); + Quux(int i); + Quux(char c); + Quux(Foo f); +private: + int priv; +}; + + class DLL_API Qux { public: @@ -216,6 +228,21 @@ private: #define DEFAULT_INT (2 * 1000UL + 500UL) +namespace Qt +{ + enum GlobalColor { + black, + white, + }; +} + +class QColor +{ +public: + QColor(); + QColor(Qt::GlobalColor color); +}; + class DLL_API MethodsWithDefaultValues { public: @@ -236,7 +263,11 @@ public: void defaultNonEmptyCtor(QGenericArgument arg = QGenericArgument(0)); void defaultMappedToEnum(QFlags qFlags = Flags::Flag1); void defaultMappedToZeroEnum(QFlags qFlags = 0); + void defaultImplicitCtorInt(Quux arg = 0); + void defaultImplicitCtorChar(Quux arg = 'a'); + void defaultImplicitCtorFoo(Quux arg = Foo()); void defaultIntWithLongExpression(unsigned int i = DEFAULT_INT); + void defaultRefTypeEnumImplicitCtor(const QColor &fillColor = Qt::white); }; class DLL_API HasPrivateOverrideBase