diff --git a/src/AST/Expression.cs b/src/AST/Expression.cs index 24e89cd9..03b5547b 100644 --- a/src/AST/Expression.cs +++ b/src/AST/Expression.cs @@ -1,8 +1,6 @@ -using System; - namespace CppSharp.AST { - public abstract class Expression + public abstract class Expression : Statement { public string DebugText; diff --git a/src/AST/Function.cs b/src/AST/Function.cs index 74bb8930..f509a9ab 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -46,6 +46,7 @@ namespace CppSharp.AST Kind = p.Kind; QualifiedType = p.QualifiedType; Usage = p.Usage; + DefaultArgument = p.DefaultArgument; } public Type Type { get { return QualifiedType.Type; } } @@ -57,6 +58,8 @@ namespace CppSharp.AST public ParameterUsage Usage { get; set; } public bool HasDefaultValue { get; set; } + public Expression DefaultArgument { get; set; } + public bool IsIn { get { return Usage == ParameterUsage.In; } } public bool IsOut { get { return Usage == ParameterUsage.Out; } } public bool IsInOut { get { return Usage == ParameterUsage.InOut; } } diff --git a/src/AST/Statement.cs b/src/AST/Statement.cs new file mode 100644 index 00000000..b1ae1985 --- /dev/null +++ b/src/AST/Statement.cs @@ -0,0 +1,16 @@ +namespace CppSharp.AST +{ + public enum StatementClass + { + Any, + DeclarationReference, + ConstructorReference + } + + public abstract class Statement + { + public StatementClass Class { get; set; } + public Declaration Declaration { get; set; } + public string String { get; set; } + } +} diff --git a/src/Core/Parser/ASTConverter.cs b/src/Core/Parser/ASTConverter.cs index 6b7f7d24..211d5414 100644 --- a/src/Core/Parser/ASTConverter.cs +++ b/src/Core/Parser/ASTConverter.cs @@ -833,10 +833,31 @@ namespace CppSharp _param.IsIndirect = decl.IsIndirect; _param.HasDefaultValue = decl.HasDefaultValue; _param.Index = decl.Index; + _param.DefaultArgument = VisitStatement(decl.DefaultArgument); return _param; } + private AST.Expression VisitStatement(Statement statement) + { + if (statement == null) + return null; + + var expression = new AST.BuiltinTypeExpression(); + expression.Declaration = this.typeConverter.declConverter.Visit(statement.Decl); + expression.String = statement.String; + switch (statement.Class) + { + case StatementClass.DeclRefExprClass: + expression.Class = AST.StatementClass.DeclarationReference; + break; + case StatementClass.CXXConstructExprClass: + expression.Class = AST.StatementClass.ConstructorReference; + break; + } + return expression; + } + public void VisitFunction(Function function, AST.Function _function) { VisitDeclaration(function, _function); diff --git a/src/CppParser/AST.cpp b/src/CppParser/AST.cpp index 80fc6ddb..c76ee354 100644 --- a/src/CppParser/AST.cpp +++ b/src/CppParser/AST.cpp @@ -418,8 +418,14 @@ TypedefDecl* DeclarationContext::FindTypedef(const std::string& Name, bool Creat TypedefDecl::TypedefDecl() : Declaration(DeclarationKind::Typedef) {} +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) {} + Parameter::Parameter() : Declaration(DeclarationKind::Parameter), - IsIndirect(false), HasDefaultValue(false) {} + IsIndirect(false), HasDefaultValue(false), DefaultArgument(0) {} Function::Function() : Declaration(DeclarationKind::Function) diff --git a/src/CppParser/AST.h b/src/CppParser/AST.h index 996346e8..687c2dcf 100644 --- a/src/CppParser/AST.h +++ b/src/CppParser/AST.h @@ -455,6 +455,28 @@ public: CppSharp::CppParser::AST::QualifiedType QualifiedType; }; +enum class StatementClass +{ + Any, + DeclRefExprClass, + CXXConstructExprClass +}; + +class CS_API Statement +{ +public: + Statement(const std::string& str, StatementClass Class = StatementClass::Any, Declaration* decl = 0); + StatementClass Class; + Declaration* Decl; + STRING(String) +}; + +class CS_API Expression : public Statement +{ +public: + Expression(const std::string& str, StatementClass Class = StatementClass::Any, Declaration* decl = 0); +}; + class CS_API Parameter : public Declaration { public: @@ -464,6 +486,7 @@ public: bool IsIndirect; bool HasDefaultValue; unsigned int Index; + Expression* DefaultArgument; }; enum class CXXMethodKind diff --git a/src/CppParser/Bindings/CLI/AST.cpp b/src/CppParser/Bindings/CLI/AST.cpp index 4aa7df9c..96a10aa1 100644 --- a/src/CppParser/Bindings/CLI/AST.cpp +++ b/src/CppParser/Bindings/CLI/AST.cpp @@ -1465,6 +1465,72 @@ void CppSharp::Parser::AST::TypedefDecl::QualifiedType::set(CppSharp::Parser::AS ((::CppSharp::CppParser::AST::TypedefDecl*)NativePtr)->QualifiedType = *(::CppSharp::CppParser::AST::QualifiedType*)value->NativePtr; } +CppSharp::Parser::AST::Statement::Statement(::CppSharp::CppParser::AST::Statement* native) +{ + NativePtr = native; +} + +CppSharp::Parser::AST::Statement::Statement(System::IntPtr native) +{ + auto __native = (::CppSharp::CppParser::AST::Statement*)native.ToPointer(); + NativePtr = __native; +} + +System::IntPtr CppSharp::Parser::AST::Statement::__Instance::get() +{ + return System::IntPtr(NativePtr); +} + +void CppSharp::Parser::AST::Statement::__Instance::set(System::IntPtr object) +{ + NativePtr = (::CppSharp::CppParser::AST::Statement*)object.ToPointer(); +} + +System::String^ CppSharp::Parser::AST::Statement::String::get() +{ + auto __ret = ((::CppSharp::CppParser::AST::Statement*)NativePtr)->getString(); + if (__ret == nullptr) return nullptr; + return clix::marshalString(__ret); +} + +void CppSharp::Parser::AST::Statement::String::set(System::String^ s) +{ + auto _arg0 = clix::marshalString(s); + auto arg0 = _arg0.c_str(); + ((::CppSharp::CppParser::AST::Statement*)NativePtr)->setString(arg0); +} + +CppSharp::Parser::AST::StatementClass CppSharp::Parser::AST::Statement::Class::get() +{ + return (CppSharp::Parser::AST::StatementClass)((::CppSharp::CppParser::AST::Statement*)NativePtr)->Class; +} + +void CppSharp::Parser::AST::Statement::Class::set(CppSharp::Parser::AST::StatementClass value) +{ + ((::CppSharp::CppParser::AST::Statement*)NativePtr)->Class = (::CppSharp::CppParser::AST::StatementClass)value; +} + +CppSharp::Parser::AST::Declaration^ CppSharp::Parser::AST::Statement::Decl::get() +{ + return (((::CppSharp::CppParser::AST::Statement*)NativePtr)->Decl == nullptr) ? nullptr : gcnew CppSharp::Parser::AST::Declaration((::CppSharp::CppParser::AST::Declaration*)((::CppSharp::CppParser::AST::Statement*)NativePtr)->Decl); +} + +void CppSharp::Parser::AST::Statement::Decl::set(CppSharp::Parser::AST::Declaration^ value) +{ + ((::CppSharp::CppParser::AST::Statement*)NativePtr)->Decl = (::CppSharp::CppParser::AST::Declaration*)value->NativePtr; +} + +CppSharp::Parser::AST::Expression::Expression(::CppSharp::CppParser::AST::Expression* native) + : CppSharp::Parser::AST::Statement((::CppSharp::CppParser::AST::Statement*)native) +{ +} + +CppSharp::Parser::AST::Expression::Expression(System::IntPtr native) + : CppSharp::Parser::AST::Statement(native) +{ + auto __native = (::CppSharp::CppParser::AST::Expression*)native.ToPointer(); +} + CppSharp::Parser::AST::Parameter::Parameter(::CppSharp::CppParser::AST::Parameter* native) : CppSharp::Parser::AST::Declaration((::CppSharp::CppParser::AST::Declaration*)native) { @@ -1522,6 +1588,16 @@ void CppSharp::Parser::AST::Parameter::Index::set(unsigned int value) ((::CppSharp::CppParser::AST::Parameter*)NativePtr)->Index = value; } +CppSharp::Parser::AST::Expression^ CppSharp::Parser::AST::Parameter::DefaultArgument::get() +{ + return (((::CppSharp::CppParser::AST::Parameter*)NativePtr)->DefaultArgument == nullptr) ? nullptr : gcnew CppSharp::Parser::AST::Expression((::CppSharp::CppParser::AST::Expression*)((::CppSharp::CppParser::AST::Parameter*)NativePtr)->DefaultArgument); +} + +void CppSharp::Parser::AST::Parameter::DefaultArgument::set(CppSharp::Parser::AST::Expression^ value) +{ + ((::CppSharp::CppParser::AST::Parameter*)NativePtr)->DefaultArgument = (::CppSharp::CppParser::AST::Expression*)value->NativePtr; +} + CppSharp::Parser::AST::Function::Function(::CppSharp::CppParser::AST::Function* 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 39e79da1..09486ce9 100644 --- a/src/CppParser/Bindings/CLI/AST.h +++ b/src/CppParser/Bindings/CLI/AST.h @@ -20,6 +20,7 @@ namespace CppSharp enum struct MacroLocation; enum struct PrimitiveType; enum struct RawCommentKind; + enum struct StatementClass; enum struct TemplateSpecializationKind; enum struct TypeKind; enum struct VTableComponentKind; @@ -40,6 +41,7 @@ namespace CppSharp ref class DeclarationContext; ref class DependentNameType; ref class Enumeration; + ref class Expression; ref class Field; ref class FullComment; ref class Function; @@ -59,6 +61,7 @@ namespace CppSharp ref class PreprocessedEntity; ref class QualifiedType; ref class RawComment; + ref class Statement; ref class TagType; ref class Template; ref class TemplateArgument; @@ -204,6 +207,13 @@ namespace CppSharp Unknown = 5 }; + public enum struct StatementClass + { + Any = 0, + DeclRefExprClass = 1, + CXXConstructExprClass = 2 + }; + public enum struct TemplateSpecializationKind { Undeclared = 0, @@ -1127,6 +1137,46 @@ namespace CppSharp } }; + public ref class Statement : ICppInstance + { + public: + + property ::CppSharp::CppParser::AST::Statement* NativePtr; + property System::IntPtr __Instance + { + virtual System::IntPtr get(); + virtual void set(System::IntPtr instance); + } + + Statement(::CppSharp::CppParser::AST::Statement* native); + Statement(System::IntPtr native); + property System::String^ String + { + System::String^ get(); + void set(System::String^); + } + + property CppSharp::Parser::AST::StatementClass Class + { + CppSharp::Parser::AST::StatementClass get(); + void set(CppSharp::Parser::AST::StatementClass); + } + + property CppSharp::Parser::AST::Declaration^ Decl + { + CppSharp::Parser::AST::Declaration^ get(); + void set(CppSharp::Parser::AST::Declaration^); + } + }; + + public ref class Expression : CppSharp::Parser::AST::Statement + { + public: + + Expression(::CppSharp::CppParser::AST::Expression* native); + Expression(System::IntPtr native); + }; + public ref class Parameter : CppSharp::Parser::AST::Declaration { public: @@ -1158,6 +1208,12 @@ namespace CppSharp unsigned int get(); void set(unsigned int); } + + property CppSharp::Parser::AST::Expression^ DefaultArgument + { + CppSharp::Parser::AST::Expression^ get(); + void set(CppSharp::Parser::AST::Expression^); + } }; public ref class Function : CppSharp::Parser::AST::Declaration diff --git a/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/AST.cs b/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/AST.cs index 60956562..c7eaf897 100644 --- a/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/AST.cs +++ b/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/AST.cs @@ -131,6 +131,13 @@ namespace CppSharp Unknown = 5 } + public enum StatementClass + { + Any = 0, + DeclRefExprClass = 1, + CXXConstructExprClass = 2 + } + public enum TemplateSpecializationKind { Undeclared = 0, @@ -3411,9 +3418,171 @@ namespace CppSharp } } + public unsafe partial class Statement : IDisposable + { + [StructLayout(LayoutKind.Explicit, Size = 20)] + public struct Internal + { + [FieldOffset(0)] + public CppSharp.Parser.AST.StatementClass Class; + + [FieldOffset(4)] + public global::System.IntPtr Decl; + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST9StatementC2ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS1_14StatementClassEPNS1_11DeclarationE")] + internal static extern void ctor_0(global::System.IntPtr instance, global::System.IntPtr str, CppSharp.Parser.AST.StatementClass Class, global::System.IntPtr decl); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST9StatementC2ERKS2_")] + internal static extern void cctor_2(global::System.IntPtr instance, global::System.IntPtr _0); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST9StatementD2Ev")] + internal static extern void dtor_0(global::System.IntPtr instance); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST9Statement9getStringEv")] + internal static extern global::System.IntPtr getString_0(global::System.IntPtr instance); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST9Statement9setStringEPKc")] + internal static extern void setString_0(global::System.IntPtr instance, global::System.IntPtr s); + } + + public global::System.IntPtr __Instance { get; protected set; } + + internal Statement(Statement.Internal* native) + : this(new global::System.IntPtr(native)) + { + } + + internal Statement(Statement.Internal native) + : this(&native) + { + } + + public Statement(global::System.IntPtr native, bool isInternalImpl = false) + { + __Instance = native; + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + Internal.dtor_0(__Instance); + Marshal.FreeHGlobal(__Instance); + } + + public string String + { + get + { + var __ret = Internal.getString_0(__Instance); + if (__ret == global::System.IntPtr.Zero) return null; + return Marshal.PtrToStringAnsi(__ret); + } + + set + { + var arg0 = Marshal.StringToHGlobalAnsi(value); + Internal.setString_0(__Instance, arg0); + Marshal.FreeHGlobal(arg0); + } + } + + public CppSharp.Parser.AST.StatementClass Class + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return __ptr->Class; + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->Class = value; + } + } + + public CppSharp.Parser.AST.Declaration Decl + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return (__ptr->Decl == IntPtr.Zero) ? null : new CppSharp.Parser.AST.Declaration(__ptr->Decl); + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->Decl = value == (CppSharp.Parser.AST.Declaration) null ? global::System.IntPtr.Zero : value.__Instance; + } + } + } + + public unsafe partial class Expression : CppSharp.Parser.AST.Statement, IDisposable + { + [StructLayout(LayoutKind.Explicit, Size = 20)] + public new struct Internal + { + [FieldOffset(0)] + public CppSharp.Parser.AST.StatementClass Class; + + [FieldOffset(4)] + public global::System.IntPtr Decl; + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST10ExpressionC2ERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEENS1_14StatementClassEPNS1_11DeclarationE")] + internal static extern void ctor_0(global::System.IntPtr instance, global::System.IntPtr str, CppSharp.Parser.AST.StatementClass Class, global::System.IntPtr decl); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST10ExpressionC2ERKS2_")] + internal static extern void cctor_1(global::System.IntPtr instance, global::System.IntPtr _0); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, + EntryPoint="_ZN8CppSharp9CppParser3AST10ExpressionD2Ev")] + internal static extern void dtor_0(global::System.IntPtr instance); + } + + internal Expression(Expression.Internal* native) + : this(new global::System.IntPtr(native)) + { + } + + internal Expression(Expression.Internal native) + : this(&native) + { + } + + public Expression(global::System.IntPtr native, bool isInternalImpl = false) + : base(native) + { + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + } + public unsafe partial class Parameter : CppSharp.Parser.AST.Declaration, IDisposable { - [StructLayout(LayoutKind.Explicit, Size = 100)] + [StructLayout(LayoutKind.Explicit, Size = 104)] public new struct Internal { [FieldOffset(0)] @@ -3458,6 +3627,9 @@ namespace CppSharp [FieldOffset(96)] public uint Index; + [FieldOffset(100)] + public global::System.IntPtr DefaultArgument; + [SuppressUnmanagedCodeSecurity] [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint="_ZN8CppSharp9CppParser3AST9ParameterC2Ev")] @@ -3492,7 +3664,7 @@ namespace CppSharp public Parameter() : this(IntPtr.Zero) { - __Instance = Marshal.AllocHGlobal(100); + __Instance = Marshal.AllocHGlobal(104); Internal.ctor_0(__Instance); } @@ -3562,6 +3734,21 @@ namespace CppSharp __ptr->Index = value; } } + + public CppSharp.Parser.AST.Expression DefaultArgument + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return (__ptr->DefaultArgument == IntPtr.Zero) ? null : new CppSharp.Parser.AST.Expression(__ptr->DefaultArgument); + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->DefaultArgument = value == (CppSharp.Parser.AST.Expression) null ? global::System.IntPtr.Zero : value.__Instance; + } + } } public unsafe partial class Function : CppSharp.Parser.AST.Declaration, IDisposable diff --git a/src/CppParser/Bindings/CSharp/i686-pc-win32/AST.cs b/src/CppParser/Bindings/CSharp/i686-pc-win32/AST.cs index 1e67c22c..555a8feb 100644 --- a/src/CppParser/Bindings/CSharp/i686-pc-win32/AST.cs +++ b/src/CppParser/Bindings/CSharp/i686-pc-win32/AST.cs @@ -131,6 +131,13 @@ namespace CppSharp Unknown = 5 } + public enum StatementClass + { + Any = 0, + DeclRefExprClass = 1, + CXXConstructExprClass = 2 + } + public enum TemplateSpecializationKind { Undeclared = 0, @@ -3411,9 +3418,171 @@ namespace CppSharp } } + public unsafe partial class Statement : IDisposable + { + [StructLayout(LayoutKind.Explicit, Size = 32)] + public struct Internal + { + [FieldOffset(0)] + public CppSharp.Parser.AST.StatementClass Class; + + [FieldOffset(4)] + public global::System.IntPtr Decl; + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??0Statement@AST@CppParser@CppSharp@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@W4StatementClass@123@PAVDeclaration@123@@Z")] + internal static extern global::System.IntPtr ctor_0(global::System.IntPtr instance, global::System.IntPtr str, CppSharp.Parser.AST.StatementClass Class, global::System.IntPtr decl); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??0Statement@AST@CppParser@CppSharp@@QAE@ABV0123@@Z")] + internal static extern global::System.IntPtr cctor_2(global::System.IntPtr instance, global::System.IntPtr _0); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??1Statement@AST@CppParser@CppSharp@@QAE@XZ")] + internal static extern void dtor_0(global::System.IntPtr instance); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="?getString@Statement@AST@CppParser@CppSharp@@QAEPBDXZ")] + internal static extern global::System.IntPtr getString_0(global::System.IntPtr instance); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="?setString@Statement@AST@CppParser@CppSharp@@QAEXPBD@Z")] + internal static extern void setString_0(global::System.IntPtr instance, global::System.IntPtr s); + } + + public global::System.IntPtr __Instance { get; protected set; } + + internal Statement(Statement.Internal* native) + : this(new global::System.IntPtr(native)) + { + } + + internal Statement(Statement.Internal native) + : this(&native) + { + } + + public Statement(global::System.IntPtr native, bool isInternalImpl = false) + { + __Instance = native; + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + Internal.dtor_0(__Instance); + Marshal.FreeHGlobal(__Instance); + } + + public string String + { + get + { + var __ret = Internal.getString_0(__Instance); + if (__ret == global::System.IntPtr.Zero) return null; + return Marshal.PtrToStringAnsi(__ret); + } + + set + { + var arg0 = Marshal.StringToHGlobalAnsi(value); + Internal.setString_0(__Instance, arg0); + Marshal.FreeHGlobal(arg0); + } + } + + public CppSharp.Parser.AST.StatementClass Class + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return __ptr->Class; + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->Class = value; + } + } + + public CppSharp.Parser.AST.Declaration Decl + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return (__ptr->Decl == IntPtr.Zero) ? null : new CppSharp.Parser.AST.Declaration(__ptr->Decl); + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->Decl = value == (CppSharp.Parser.AST.Declaration) null ? global::System.IntPtr.Zero : value.__Instance; + } + } + } + + public unsafe partial class Expression : CppSharp.Parser.AST.Statement, IDisposable + { + [StructLayout(LayoutKind.Explicit, Size = 32)] + public new struct Internal + { + [FieldOffset(0)] + public CppSharp.Parser.AST.StatementClass Class; + + [FieldOffset(4)] + public global::System.IntPtr Decl; + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??0Expression@AST@CppParser@CppSharp@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@W4StatementClass@123@PAVDeclaration@123@@Z")] + internal static extern global::System.IntPtr ctor_0(global::System.IntPtr instance, global::System.IntPtr str, CppSharp.Parser.AST.StatementClass Class, global::System.IntPtr decl); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??0Expression@AST@CppParser@CppSharp@@QAE@ABV0123@@Z")] + internal static extern global::System.IntPtr cctor_1(global::System.IntPtr instance, global::System.IntPtr _0); + + [SuppressUnmanagedCodeSecurity] + [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, + EntryPoint="??1Expression@AST@CppParser@CppSharp@@QAE@XZ")] + internal static extern void dtor_0(global::System.IntPtr instance); + } + + internal Expression(Expression.Internal* native) + : this(new global::System.IntPtr(native)) + { + } + + internal Expression(Expression.Internal native) + : this(&native) + { + } + + public Expression(global::System.IntPtr native, bool isInternalImpl = false) + : base(native) + { + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + } + public unsafe partial class Parameter : CppSharp.Parser.AST.Declaration, IDisposable { - [StructLayout(LayoutKind.Explicit, Size = 136)] + [StructLayout(LayoutKind.Explicit, Size = 140)] public new struct Internal { [FieldOffset(0)] @@ -3458,6 +3627,9 @@ namespace CppSharp [FieldOffset(132)] public uint Index; + [FieldOffset(136)] + public global::System.IntPtr DefaultArgument; + [SuppressUnmanagedCodeSecurity] [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, EntryPoint="??0Parameter@AST@CppParser@CppSharp@@QAE@XZ")] @@ -3492,7 +3664,7 @@ namespace CppSharp public Parameter() : this(IntPtr.Zero) { - __Instance = Marshal.AllocHGlobal(136); + __Instance = Marshal.AllocHGlobal(140); Internal.ctor_0(__Instance); } @@ -3562,6 +3734,21 @@ namespace CppSharp __ptr->Index = value; } } + + public CppSharp.Parser.AST.Expression DefaultArgument + { + get + { + var __ptr = (Internal*)__Instance.ToPointer(); + return (__ptr->DefaultArgument == IntPtr.Zero) ? null : new CppSharp.Parser.AST.Expression(__ptr->DefaultArgument); + } + + set + { + var __ptr = (Internal*)__Instance.ToPointer(); + __ptr->DefaultArgument = value == (CppSharp.Parser.AST.Expression) null ? global::System.IntPtr.Zero : value.__Instance; + } + } } public unsafe partial class Function : CppSharp.Parser.AST.Declaration, IDisposable diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index 04a3b8be..07f6fbe3 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -2176,6 +2176,10 @@ 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 = WalkStatement(VD->getDefaultArg()); + } HandleDeclaration(VD, P); F->Parameters.push_back(P); @@ -2430,6 +2434,52 @@ void Parser::HandlePreprocessedEntities(Declaration* Decl) } } +AST::Expression* Parser::WalkStatement(clang::Stmt* Statement) +{ + using namespace clang; + + switch (Statement->getStmtClass()) + { + case Stmt::DeclRefExprClass: + return new AST::Expression(GetStringFromStatement(Statement), StatementClass::DeclRefExprClass, + WalkDeclaration(cast(Statement)->getDecl())); + case Stmt::CStyleCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXFunctionalCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::ImplicitCastExprClass: + return WalkStatement(cast(Statement)->getSubExprAsWritten()); + case Stmt::CXXConstructExprClass: + { + auto ConstructorExpr = cast(Statement); + auto Arg = ConstructorExpr->getArg(0); + auto TemporaryExpr = dyn_cast(Arg); + if (TemporaryExpr && isa(TemporaryExpr->GetTemporaryExpr())) + return WalkStatement(TemporaryExpr->GetTemporaryExpr()); + return new AST::Expression(GetStringFromStatement(Statement), StatementClass::CXXConstructExprClass, + WalkDeclaration(ConstructorExpr->getConstructor())); + } + case Stmt::MaterializeTemporaryExprClass: + return WalkStatement(cast(Statement)->GetTemporaryExpr()); + default: + break; + } + return new AST::Expression(GetStringFromStatement(Statement)); +} + +std::string Parser::GetStringFromStatement(const clang::Stmt* Statement) +{ + using namespace clang; + + PrintingPolicy Policy(C->getLangOpts()); + std::string s; + llvm::raw_string_ostream as(s); + Statement->printPretty(as, 0, Policy); + return as.str(); +} + void Parser::HandlePreprocessedEntities(Declaration* Decl, clang::SourceRange sourceRange, MacroLocation macroLocation) diff --git a/src/CppParser/Parser.h b/src/CppParser/Parser.h index 52c08f72..c9b7424c 100644 --- a/src/CppParser/Parser.h +++ b/src/CppParser/Parser.h @@ -93,6 +93,8 @@ protected: VTableComponent WalkVTableComponent(const clang::VTableComponent& Component); PreprocessedEntity* WalkPreprocessedEntity(Declaration* Decl, clang::PreprocessedEntity* PPEntity); + AST::Expression* WalkStatement(clang::Stmt* Statement); + std::string GetStringFromStatement(const clang::Stmt* Statement); // Clang helpers SourceLocationKind GetLocationKind(const clang::SourceLocation& Loc); diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 6578f1e3..7d544b62 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -236,6 +236,8 @@ namespace CppSharp TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); TranslationUnitPasses.AddPass(new CheckFlagEnumsPass()); TranslationUnitPasses.AddPass(new CheckDuplicatedNamesPass()); + if (Options.IsCSharpGenerator && Options.GenerateDefaultValuesForArguments) + TranslationUnitPasses.AddPass(new HandleDefaultParamValuesPass()); if (Options.GenerateAbstractImpls) TranslationUnitPasses.AddPass(new GenerateAbstractImplementationsPass()); diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 90464cfc..40b6727d 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -2051,6 +2051,19 @@ namespace CppSharp.Generators.CSharp if (method.IsProxy) goto SkipImpl; + if (method.SynthKind == FunctionSynthKind.DefaultValueOverload) + { + Type type = method.OriginalReturnType.Type; + WriteLine("{0}{1}({2});", + type.IsPrimitiveType(PrimitiveType.Void) ? string.Empty : "return ", + method.Name, + string.Join(", ", + method.Parameters.Where( + p => p.Kind == ParameterKind.Regular).Select( + p => p.GenerationKind == GenerationKind.None ? p.DefaultArgument.String : p.Name))); + goto SkipImpl; + } + if (@class.IsRefType) { if (method.IsConstructor) @@ -2534,10 +2547,12 @@ namespace CppSharp.Generators.CSharp { return string.Join(", ", from param in @params - where param.Kind != ParameterKind.IndirectReturnType - let typeName = param.CSharpType(TypePrinter) + where param.Kind != ParameterKind.IndirectReturnType && !param.Ignore + let typeName = param.CSharpType(this.TypePrinter) select string.Format("{0}{1} {2}", GetParameterUsage(param.Usage), - typeName, param.Name)); + typeName, param.Name + + (param.DefaultArgument == null || !Options.GenerateDefaultValuesForArguments ? + string.Empty : " = " + param.DefaultArgument.String))); } #endregion diff --git a/src/Generator/Options.cs b/src/Generator/Options.cs index 01ad2970..f64a2f38 100644 --- a/src/Generator/Options.cs +++ b/src/Generator/Options.cs @@ -180,6 +180,11 @@ namespace CppSharp /// Generates a single C# file. /// public bool GenerateSingleCSharpFile { get; set; } + + /// + /// Generates default values of arguments in the C# code. + /// + public bool GenerateDefaultValuesForArguments { get; set; } } public class InvalidOptionException : Exception diff --git a/src/Generator/Passes/HandleDefaultParamValuesPass.cs b/src/Generator/Passes/HandleDefaultParamValuesPass.cs new file mode 100644 index 00000000..71d5252d --- /dev/null +++ b/src/Generator/Passes/HandleDefaultParamValuesPass.cs @@ -0,0 +1,173 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using CppSharp.AST; +using CppSharp.AST.Extensions; +using CppSharp.Generators.CLI; +using CppSharp.Generators.CSharp; +using CppSharp.Types; +using Type = CppSharp.AST.Type; + +namespace CppSharp.Passes +{ + public class HandleDefaultParamValuesPass : TranslationUnitPass + { + 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); + + public override bool VisitFunctionDecl(Function function) + { + bool result = base.VisitFunctionDecl(function); + + var overloadIndices = new List(function.Parameters.Count); + foreach (var parameter in function.Parameters.Where(p => p.DefaultArgument != null)) + { + Type desugared = parameter.Type.Desugar(); + + if (CheckForDefaultPointer(desugared, parameter)) + continue; + + bool? defaultConstruct = CheckForDefaultConstruct(desugared, parameter); + if (defaultConstruct == null || + (!Driver.Options.MarshalCharAsManagedChar && + parameter.Type.Desugar().IsPrimitiveType(PrimitiveType.UChar))) + { + overloadIndices.Add(function.Parameters.IndexOf(parameter)); + continue; + } + if (defaultConstruct == true) + continue; + + if (CheckForEnumValue(parameter, desugared)) + continue; + + CheckForULongValue(parameter, desugared); + } + + GenerateOverloads(function, overloadIndices); + + return result; + } + + private static bool CheckForDefaultPointer(Type desugared, Parameter parameter) + { + if (desugared.IsPointer()) + { + parameter.DefaultArgument.String = "null"; + return true; + } + return false; + } + + private bool? CheckForDefaultConstruct(Type desugared, Parameter parameter) + { + Method ctor = parameter.DefaultArgument.Declaration as Method; + if (ctor == null || !ctor.IsConstructor) + return false; + + Type type; + desugared.IsPointerTo(out type); + type = type ?? desugared; + Class decl; + if (!type.TryGetClass(out decl)) + return false; + TypeMap typeMap; + + if (Driver.TypeDatabase.FindTypeMap(decl, type, out typeMap)) + { + string mappedTo; + if (Driver.Options.IsCSharpGenerator) + { + var typePrinterContext = new CSharpTypePrinterContext + { + CSharpKind = CSharpTypePrinterContextKind.Managed, + Type = type + }; + mappedTo = typeMap.CSharpSignature(typePrinterContext); + } + else + { + var typePrinterContext = new CLITypePrinterContext + { + Type = type + }; + mappedTo = typeMap.CLISignature(typePrinterContext); + } + if (mappedTo == "string" && ctor.Parameters.Count == 0) + { + parameter.DefaultArgument.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)", "()"); + + return decl.IsValueType ? true : (bool?) null; + } + + private static bool CheckForEnumValue(Parameter parameter, Type desugared) + { + var enumItem = parameter.DefaultArgument.Declaration as Enumeration.Item; + if (enumItem != null) + { + parameter.DefaultArgument.String = string.Format("{0}{1}.{2}.{3}", + desugared.IsPrimitiveType() ? "(int) " : string.Empty, + enumItem.Namespace.Namespace.Name, enumItem.Namespace.Name, enumItem.Name); + return true; + } + + var call = parameter.DefaultArgument.Declaration as Method; + if (call != null && call.IsConstructor) + { + string @params = + regexFunctionParams.Match(parameter.DefaultArgument.String).Groups[1].Value; + if (@params.Contains("::")) + parameter.DefaultArgument.String = regexDoubleColon.Replace(@params, desugared + "."); + else + parameter.DefaultArgument.String = regexName.Replace(@params, desugared + ".$1"); + return true; + } + return false; + } + + private static void CheckForULongValue(Parameter parameter, Type desugared) + { + ulong value; + string @default = parameter.DefaultArgument.String; + // HACK: .NET's Parse/TryParse have a bug preventing them from parsing UL-suffixed ulongs + if (desugared.IsPrimitiveType() && @default.EndsWith("UL")) + @default = @default.Substring(0, @default.Length - 2); + if (ulong.TryParse(@default, out value)) + parameter.DefaultArgument.String = value.ToString(CultureInfo.InvariantCulture); + } + + private static void GenerateOverloads(Function function, List overloadIndices) + { + foreach (var overloadIndex in overloadIndices) + { + var method = function as Method; + Function overload = method != null ? new Method(method) : new Function(function); + overload.SynthKind = FunctionSynthKind.DefaultValueOverload; + overload.Parameters[overloadIndex].GenerationKind = GenerationKind.None; + + var indices = overloadIndices.Where(i => i != overloadIndex).ToList(); + if (indices.Any()) + for (int i = 0; i <= indices.Last(); i++) + if (i != overloadIndex) + overload.Parameters[i].DefaultArgument = null; + + if (method != null) + ((Class) function.Namespace).Methods.Add((Method) overload); + else + function.Namespace.Functions.Add(overload); + + for (int i = 0; i <= overloadIndex; i++) + function.Parameters[i].DefaultArgument = null; + } + } + } +} diff --git a/tests/CSharpTemp/CSharpTemp.Tests.cs b/tests/CSharpTemp/CSharpTemp.Tests.cs index c8200aef..5dac132e 100644 --- a/tests/CSharpTemp/CSharpTemp.Tests.cs +++ b/tests/CSharpTemp/CSharpTemp.Tests.cs @@ -118,10 +118,24 @@ public class CSharpTempTests : GeneratorTestFixture Assert.That(testCopyConstructorVal.B, Is.EqualTo(copyBar.B)); } + [Test] public void TestPropertiesConflictingWithMethod() { var p = new P((IQux) new Qux()) { Test = true }; Assert.That(p.Test, Is.True); p.GetTest(); } + + [Test] + public void TestDefaultArguments() + { + var methodsWithDefaultValues = new MethodsWithDefaultValues(); + methodsWithDefaultValues.DefaultChar(); + methodsWithDefaultValues.DefaultPointer(); + methodsWithDefaultValues.DefaultRefTypeAfterOthers(); + methodsWithDefaultValues.DefaultRefTypeBeforeAndAfterOthers(5, new Foo()); + methodsWithDefaultValues.DefaultRefTypeBeforeOthers(); + methodsWithDefaultValues.DefaultValueType(); + methodsWithDefaultValues.DefaultIntAssignedAnEnum(); + } } \ No newline at end of file diff --git a/tests/CSharpTemp/CSharpTemp.cpp b/tests/CSharpTemp/CSharpTemp.cpp index 19b5862c..c2301bbe 100644 --- a/tests/CSharpTemp/CSharpTemp.cpp +++ b/tests/CSharpTemp/CSharpTemp.cpp @@ -206,3 +206,31 @@ TestCopyConstructorVal::TestCopyConstructorVal(const TestCopyConstructorVal& oth A = other.A; B = other.B; } + +void MethodsWithDefaultValues::DefaultPointer(Foo *ptr) +{ +} + +void MethodsWithDefaultValues::DefaultValueType(ValueType bar) +{ +} + +void MethodsWithDefaultValues::DefaultChar(char c) +{ +} + +void MethodsWithDefaultValues::DefaultRefTypeBeforeOthers(Foo foo, int i, Bar::Items item) +{ +} + +void MethodsWithDefaultValues::DefaultRefTypeAfterOthers(int i, Bar::Items item, Foo foo) +{ +} + +void MethodsWithDefaultValues::DefaultRefTypeBeforeAndAfterOthers(int i, Foo foo, Bar::Items item, Baz baz) +{ +} + +void MethodsWithDefaultValues::DefaultIntAssignedAnEnum(int i) +{ +} diff --git a/tests/CSharpTemp/CSharpTemp.cs b/tests/CSharpTemp/CSharpTemp.cs index e58add3f..91525525 100644 --- a/tests/CSharpTemp/CSharpTemp.cs +++ b/tests/CSharpTemp/CSharpTemp.cs @@ -67,6 +67,8 @@ namespace CppSharp.Tests // are not ambiguous with multiple inheritance pass enabled. driver.Options.GenerateConversionOperators = true; driver.TranslationUnitPasses.AddPass(new TestAttributesPass()); + driver.Options.MarshalCharAsManagedChar = true; + driver.Options.GenerateDefaultValuesForArguments = true; } public override void Preprocess(Driver driver, ASTContext ctx) diff --git a/tests/CSharpTemp/CSharpTemp.h b/tests/CSharpTemp/CSharpTemp.h index 457c87c7..9c1902fc 100644 --- a/tests/CSharpTemp/CSharpTemp.h +++ b/tests/CSharpTemp/CSharpTemp.h @@ -27,6 +27,11 @@ public: class DLL_API Bar : public Qux { public: + enum Items + { + Item1, + Item2 + }; Bar(); int method(); const Foo& operator[](int i) const; @@ -165,3 +170,19 @@ public: void name(); void Name(); }; + +struct DLL_API ValueType +{ +}; + +class DLL_API MethodsWithDefaultValues +{ +public: + void DefaultPointer(Foo* ptr = 0); + void DefaultValueType(ValueType bar = ValueType()); + void DefaultChar(char c = 'a'); + void DefaultRefTypeBeforeOthers(Foo foo = Foo(), int i = 5, Bar::Items item = Bar::Item2); + void DefaultRefTypeAfterOthers(int i = 5, Bar::Items item = Bar::Item2, Foo foo = Foo()); + void DefaultRefTypeBeforeAndAfterOthers(int i = 5, Foo foo = Foo(), Bar::Items item = Bar::Item2, Baz baz = Baz()); + void DefaultIntAssignedAnEnum(int i = Bar::Item1); +};