From 99f643d13f95c5551e4a70dd265021809596dcfa Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Fri, 28 Nov 2014 18:15:22 +0200 Subject: [PATCH] Test that demonstrate the "new 0" and show some other erroneus behaviour too. Implemented CastExpression. ImplicitCast and ExplicitCast statement classes. Fixed implicit constructor string generation. Implemented CtorExpr. All test cases pass. Fixed indentations, streamlined the code. Fixed regressions. Fixed regressions. Adding a test case not covered before. Fixed, refactored and simplified things. Still more fixes (0 to null ptr conversion, enum check). The additional test passes now too. --- src/AST/Expression.cs | 23 +++- src/AST/Statement.cs | 4 +- src/Core/Parser/ASTConverter.cs | 39 +++++- src/CppParser/AST.cpp | 3 +- src/CppParser/AST.h | 7 +- src/CppParser/Bindings/CLI/AST.cpp | 10 ++ src/CppParser/Bindings/CLI/AST.h | 9 +- .../Bindings/CSharp/i686-pc-win32-msvc/AST.cs | 26 +++- src/CppParser/Parser.cpp | 28 +++-- .../CSharp/CSharpExpressionPrinter.cs | 7 +- .../Passes/HandleDefaultParamValuesPass.cs | 114 +++++++++++++++--- tests/CSharpTemp/CSharpTemp.cpp | 45 +++++++ tests/CSharpTemp/CSharpTemp.h | 31 +++++ 13 files changed, 298 insertions(+), 48 deletions(-) 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