diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index f598ab51..b8490b3c 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -2281,10 +2281,11 @@ void Parser::WalkFunction(clang::FunctionDecl* FD, Function* F, P->HasDefaultValue = VD->hasDefaultArg(); P->_Namespace = NS; P->Index = VD->getFunctionScopeIndex(); - if (VD->hasDefaultArg() && !VD->hasUnparsedDefaultArg() && !VD->hasUninstantiatedDefaultArg()) - { - P->DefaultArgument = WalkExpression(VD->getDefaultArg()); - } + if (VD->hasDefaultArg() && !VD->hasUnparsedDefaultArg()) + if (VD->hasUninstantiatedDefaultArg()) + P->DefaultArgument = WalkExpression(VD->getUninstantiatedDefaultArg()); + else + P->DefaultArgument = WalkExpression(VD->getDefaultArg()); HandleDeclaration(VD, P); F->Parameters.push_back(P); @@ -2630,9 +2631,12 @@ AST::Expression* Parser::WalkExpression(clang::Expr* Expr) auto TemporaryExpr = dyn_cast(Arg); if (TemporaryExpr) { - auto Cast = dyn_cast(TemporaryExpr->GetTemporaryExpr()); - if (Cast && Cast->getSubExprAsWritten()->getStmtClass() != Stmt::IntegerLiteralClass) - return WalkExpression(Cast->getSubExprAsWritten()); + auto SubTemporaryExpr = TemporaryExpr->GetTemporaryExpr(); + auto Cast = dyn_cast(SubTemporaryExpr); + if (!Cast || Cast->getSubExprAsWritten()->getStmtClass() != Stmt::IntegerLiteralClass) + return WalkExpression(SubTemporaryExpr); + return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, + WalkDeclaration(ConstructorExpr->getConstructor()), WalkExpression(SubTemporaryExpr)); } } return new AST::Expression(GetStringFromStatement(Expr), StatementClass::CXXConstructExprClass, diff --git a/src/Generator/Passes/HandleDefaultParamValuesPass.cs b/src/Generator/Passes/HandleDefaultParamValuesPass.cs index 12d934bc..2edaaade 100644 --- a/src/Generator/Passes/HandleDefaultParamValuesPass.cs +++ b/src/Generator/Passes/HandleDefaultParamValuesPass.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; - using CppSharp.AST; using CppSharp.AST.Extensions; using CppSharp.Generators; @@ -17,7 +16,8 @@ namespace CppSharp.Passes private static readonly Regex regexName = new Regex(@"(\w+)", RegexOptions.Compiled); private static readonly Regex regexCtor = new Regex(@"^([\w<,>:]+)\s*(\([\w, ]*\))$", RegexOptions.Compiled); - private readonly Dictionary> overloads = new Dictionary>(); + private readonly Dictionary> overloads = + new Dictionary>(); public HandleDefaultParamValuesPass() { @@ -50,8 +50,8 @@ namespace CppSharp.Passes CheckFloatSyntax(desugared, parameter); - bool? defaultConstruct = CheckForDefaultConstruct(desugared, parameter.DefaultArgument, - parameter.QualifiedType.Qualifiers); + bool? defaultConstruct = CheckForDefaultConstruct(desugared, + parameter.DefaultArgument, parameter.QualifiedType.Qualifiers); if (defaultConstruct == null || (!Driver.Options.MarshalCharAsManagedChar && parameter.Type.Desugar().IsPrimitiveType(PrimitiveType.UChar)) || @@ -86,7 +86,8 @@ namespace CppSharp.Passes { case PrimitiveType.Float: if (parameter.DefaultArgument.String.EndsWith(".F")) - parameter.DefaultArgument.String = parameter.DefaultArgument.String.Replace(".F", ".0F"); + parameter.DefaultArgument.String = + parameter.DefaultArgument.String.Replace(".F", ".0F"); break; case PrimitiveType.Double: if (parameter.DefaultArgument.String.EndsWith(".")) @@ -121,7 +122,8 @@ namespace CppSharp.Passes return false; } - private bool? CheckForDefaultConstruct(Type desugared, Expression arg, TypeQualifiers qualifiers) + private bool? CheckForDefaultConstruct(Type desugared, Statement arg, + TypeQualifiers qualifiers) { // Unwrapping the underlying type behind a possible pointer/reference Type type = desugared.GetFinalPointee() ?? desugared; @@ -142,7 +144,8 @@ namespace CppSharp.Passes string typePrinterResult = null; if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap)) { - var typeInSignature = typeMap.CSharpSignatureType(typePrinterContext).SkipPointerRefs(); + var typeInSignature = typeMap.CSharpSignatureType( + typePrinterContext).SkipPointerRefs().Desugar(); Enumeration @enum; if (typeInSignature.TryGetEnum(out @enum)) return false; @@ -166,10 +169,12 @@ namespace CppSharp.Passes var templateSpecializationType = type as TemplateSpecializationType; var typePrinter = new CSharpTypePrinter(Driver); typePrinterResult = typePrinterResult ?? (templateSpecializationType != null - ? typePrinter.VisitTemplateSpecializationType(templateSpecializationType, qualifiers) + ? typePrinter.VisitTemplateSpecializationType( + templateSpecializationType, qualifiers) : typePrinter.VisitClassDecl((Class) ctor.Namespace)).Type; - arg.String = string.Format("new {0}{1}", typePrinterResult, match.Groups[2].Value); + arg.String = string.Format("new {0}{1}", typePrinterResult, + match.Groups[2].Value); if (ctor.Parameters.Count > 0 && ctor.Parameters[0].Type.IsAddress()) arg.String = arg.String.Replace("(0)", "()"); } @@ -183,7 +188,7 @@ namespace CppSharp.Passes var finalPointee = ctor.Parameters[0].Type.SkipPointerRefs().Desugar(); Enumeration @enum; if (finalPointee.TryGetEnum(out @enum)) - TranslateEnumExpression(arg, finalPointee, arg.String); + TranslateEnumExpression(ctor, arg, finalPointee, arg.String); } } @@ -209,7 +214,8 @@ namespace CppSharp.Passes { arg.String = string.Format("{0}{1}.{2}", desugared.IsPrimitiveType() ? "(int) " : string.Empty, - new CSharpTypePrinter(Driver).VisitEnumDecl((Enumeration) enumItem.Namespace), enumItem.Name); + new CSharpTypePrinter(Driver).VisitEnumDecl( + (Enumeration) enumItem.Namespace), enumItem.Name); return true; } @@ -217,23 +223,52 @@ namespace CppSharp.Passes if (call != null && arg.String != "0") { string @params = regexFunctionParams.Match(arg.String).Groups[1].Value; - TranslateEnumExpression(arg, desugared, @params); + TranslateEnumExpression(call, arg, desugared, @params); return true; } return false; } - private static void TranslateEnumExpression(Expression arg, Type desugared, string @params) + private void TranslateEnumExpression(Function function, Statement arg, + Type desugared, string @params) { + TypeMap typeMap; + if ((function.Parameters.Count == 0 || + HasSingleZeroExpression(function)) && + Driver.TypeDatabase.FindTypeMap(desugared, out typeMap)) + { + var typeInSignature = typeMap.CSharpSignatureType(new CSharpTypePrinterContext + { + CSharpKind = CSharpTypePrinterContextKind.DefaultExpression, + Type = desugared + }).SkipPointerRefs().Desugar(); + Enumeration @enum; + if (typeInSignature.TryGetEnum(out @enum)) + { + arg.String = "0"; + return; + } + } if (@params.Contains("::")) arg.String = regexDoubleColon.Replace(@params, desugared + "."); else arg.String = regexName.Replace(@params, desugared + ".$1"); } + private static bool HasSingleZeroExpression(Function function) + { + if (function.Parameters.Count != 1) + return false; + + var defaultArgument = function.Parameters[0].DefaultArgument; + return defaultArgument is BuiltinTypeExpression && + ((BuiltinTypeExpression) defaultArgument).Value == 0; + } + private void CheckForDefaultEmptyChar(Parameter parameter, Type desugared) { - if (parameter.DefaultArgument.String == "0" && Driver.Options.MarshalCharAsManagedChar && + if (parameter.DefaultArgument.String == "0" && + Driver.Options.MarshalCharAsManagedChar && desugared.IsPrimitiveType(PrimitiveType.Char)) { parameter.DefaultArgument.String = "'\\0'"; diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index 90ba587e..14ac6910 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -188,6 +188,7 @@ public class CSharpTempTests : GeneratorTestFixture methodsWithDefaultValues.DefaultNonEmptyCtor(); methodsWithDefaultValues.DefaultMappedToEnum(); methodsWithDefaultValues.DefaultMappedToZeroEnum(); + methodsWithDefaultValues.DefaultMappedToEnumAssignedWithCtor(); methodsWithDefaultValues.DefaultImplicitCtorInt(); methodsWithDefaultValues.DefaultImplicitCtorChar(); methodsWithDefaultValues.DefaultImplicitCtorFoo(); diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp index 2854c26a..ab2ef62d 100644 --- a/tests/CSharpTemp/CSharpTemp.cpp +++ b/tests/CSharpTemp/CSharpTemp.cpp @@ -216,22 +216,6 @@ long P::prop() return m_property + 100; } -template -QFlags::QFlags(T t) : flag(t) -{ -} - -template -QFlags::QFlags(Zero) : flag(0) -{ -} - -template -QFlags::operator T() -{ - return flag; -} - ComplexType::ComplexType() : qFlags(QFlags(TestFlag::Flag2)) { } @@ -420,6 +404,10 @@ void MethodsWithDefaultValues::defaultMappedToZeroEnum(QFlags qFlags) { } +void MethodsWithDefaultValues::defaultMappedToEnumAssignedWithCtor(QFlags qFlags) +{ +} + void MethodsWithDefaultValues::defaultImplicitCtorInt(Quux arg) { } diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index 726544e0..00069626 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -148,15 +148,32 @@ Proprietor::Proprietor() {} template class DLL_API QFlags { + typedef int Int; typedef int (*Zero); public: QFlags(T t); - QFlags(Zero); - operator T(); + QFlags(Zero = 0); + operator Int(); private: - T flag; + int flag; }; +template +QFlags::QFlags(T t) : flag(Int(t)) +{ +} + +template +QFlags::QFlags(Zero) : flag(Int(0)) +{ +} + +template +QFlags::operator Int() +{ + return flag; +} + enum class TestFlag { Flag1, @@ -311,6 +328,7 @@ public: void defaultNonEmptyCtor(QGenericArgument arg = QGenericArgument(0)); void defaultMappedToEnum(QFlags qFlags = Flags::Flag1); void defaultMappedToZeroEnum(QFlags qFlags = 0); + void defaultMappedToEnumAssignedWithCtor(QFlags qFlags = QFlags()); void defaultImplicitCtorInt(Quux arg = 0); void defaultImplicitCtorChar(Quux arg = 'a'); void defaultImplicitCtorFoo(Quux arg = Foo());