From ec9250872682c6829d52b960a656b16b62120576 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Mon, 2 Sep 2013 21:25:38 +0300 Subject: [PATCH 01/20] Moved the finding of symbols after the custom passes. Gave a default value to the output dir. Signed-off-by: Dimitar Dobrev --- src/Generator/Driver.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 1e153420..5a7dacfa 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -133,16 +133,16 @@ namespace CppSharp TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass()); TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); + + library.SetupPasses(this); + TranslationUnitPasses.AddPass(new FindSymbolsPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass()); TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); - library.SetupPasses(this); - Generator.SetupPasses(); - TranslationUnitPasses.AddPass(new FieldToPropertyPass()); TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); @@ -165,7 +165,7 @@ namespace CppSharp public void WriteCode(List outputs) { - var outputPath = Options.OutputDir ?? Directory.GetCurrentDirectory(); + var outputPath = Options.OutputDir; if (!Directory.Exists(outputPath)) Directory.CreateDirectory(outputPath); @@ -208,6 +208,8 @@ namespace CppSharp SystemIncludeDirs = new List(); Headers = new List(); + OutputDir = Directory.GetCurrentDirectory(); + var platform = Environment.OSVersion.Platform; var isUnix = platform == PlatformID.Unix || platform == PlatformID.MacOSX; MicrosoftMode = !isUnix; From b6d4f0f97b932259c0f13dfa9d429317d314e529 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 3 Sep 2013 02:50:04 +0300 Subject: [PATCH 02/20] Fixed a regression caused by the returning of null. Signed-off-by: Dimitar Dobrev --- src/Generator/Generators/CSharp/CSharpTextTemplate.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 83c11c47..785ba085 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -1758,8 +1758,10 @@ namespace CppSharp.Generators.CSharp if (retType.Type.IsPointer() && isIntPtr) { - WriteLine("if ({0} == global::System.IntPtr.Zero) return null;", - Generator.GeneratedIdentifier("ret")); + string @null = retType.Type.IsPrimitiveType(PrimitiveType.IntPtr) ? + "IntPtr.Zero" : "null"; + WriteLine("if ({0} == global::System.IntPtr.Zero) return {1};", + Generator.GeneratedIdentifier("ret"), @null); } var ctx = new CSharpMarshalContext(Driver) From 42a1af65037d00b69faf71e00116f2bcc443a35a Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 3 Sep 2013 23:22:36 +0300 Subject: [PATCH 03/20] Added a pass for generating wrapper code and definitions for inlines and an option for the name of the lib with inlines. Ignored non-tag indirect return types. Signed-off-by: Dimitar Dobrev --- src/Generator/Driver.cs | 15 ++++ src/Generator/Passes/CheckIgnoredDecls.cs | 13 +++ .../Passes/GenerateInlinesCodePass.cs | 80 +++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/Generator/Passes/GenerateInlinesCodePass.cs diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 5a7dacfa..936141e9 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -133,6 +133,7 @@ namespace CppSharp TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass()); TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass()); TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass()); + TranslationUnitPasses.AddPass(new GenerateInlinesCodePass()); library.SetupPasses(this); @@ -260,6 +261,7 @@ namespace CppSharp public string OutputNamespace; public string OutputDir; public string LibraryName; + private string inlinesLibraryName; public bool OutputInteropIncludes; public bool GenerateLibraryNamespace; public bool GenerateFunctionTemplates; @@ -273,6 +275,19 @@ namespace CppSharp public int MaxIndent; public string CommentPrefix; + public string InlinesLibraryName + { + get + { + if (string.IsNullOrEmpty(inlinesLibraryName)) + { + return string.Format("{0}-inlines", OutputNamespace); + } + return inlinesLibraryName; + } + set { inlinesLibraryName = value; } + } + public bool IsCSharpGenerator { get { return GeneratorKind == LanguageGeneratorKind.CSharp; } diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index b715faba..fd888e26 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -86,6 +86,19 @@ namespace CppSharp.Passes function.Name, msg); return false; } + + if (param.Kind == ParameterKind.IndirectReturnType) + { + Class retClass; + param.Type.Desugar().IsTagDecl(out retClass); + if (retClass == null) + { + function.ExplicityIgnored = true; + Console.WriteLine("Function '{0}' was ignored due to an indirect return param not of a tag type", + function.Name); + return false; + } + } } return true; diff --git a/src/Generator/Passes/GenerateInlinesCodePass.cs b/src/Generator/Passes/GenerateInlinesCodePass.cs new file mode 100644 index 00000000..b194efa8 --- /dev/null +++ b/src/Generator/Passes/GenerateInlinesCodePass.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using CppSharp.AST; + +namespace CppSharp.Passes +{ + public class GenerateInlinesCodePass : TranslationUnitPass + { + private TranslationUnit currentUnit; + private readonly List headers = new List(); + private readonly List mangledInlines = new List(); + + public override bool VisitLibrary(Library library) + { + bool result = base.VisitLibrary(library); + var cppBuilder = new StringBuilder(); + headers.Sort(); + foreach (var header in headers) + cppBuilder.AppendFormat("#include \"{0}\"\n", header); + var cpp = string.Format("{0}.cpp", Driver.Options.InlinesLibraryName); + var path = Path.Combine(Driver.Options.OutputDir, cpp); + File.WriteAllText(path, cppBuilder.ToString()); + switch (Driver.Options.Abi) + { + case CppAbi.Microsoft: + var defBuilder = new StringBuilder("EXPORTS\r\n"); + for (int i = 0; i < mangledInlines.Count; i++) + defBuilder.AppendFormat(" {0} @{1}\r\n", + mangledInlines[i], i + 1); + File.WriteAllText(Path.ChangeExtension(path, "def"), + defBuilder.ToString()); + break; + default: + var symbolsBuilder = new StringBuilder(); + foreach (var mangledInline in mangledInlines) + symbolsBuilder.AppendFormat("{0}\n", mangledInline); + File.WriteAllText(Path.ChangeExtension(path, "txt"), + symbolsBuilder.ToString()); + break; + } + return result; + } + + public override bool VisitTranslationUnit(TranslationUnit unit) + { + currentUnit = unit; + return base.VisitTranslationUnit(unit); + } + + public override bool VisitFunctionDecl(Function function) + { + CheckForSymbols(function); + return base.VisitFunctionDecl(function); + } + + public override bool VisitVariableDecl(Variable variable) + { + CheckForSymbols(variable); + return base.VisitVariableDecl(variable); + } + + private void CheckForSymbols(IMangledDecl mangled) + { + string symbol = mangled.Mangled; + var declaration = (Declaration) mangled; + if (!declaration.Ignore && declaration.Access != AccessSpecifier.Private && + !Driver.LibrarySymbols.FindSymbol(ref symbol) && + !currentUnit.FilePath.EndsWith("_impl.h") && + !currentUnit.FilePath.EndsWith("_p.h")) + { + if (!headers.Contains(currentUnit.FileName)) + headers.Add(currentUnit.FileName); + if (!mangledInlines.Contains(mangled.Mangled)) + mangledInlines.Add(mangled.Mangled); + } + } + } +} From 22355f64ed56c1f9120b3a7d98e3fe365cde6cb8 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 4 Sep 2013 16:57:11 +0300 Subject: [PATCH 04/20] Corrected the access modifiers of methods, delegates and properties. Signed-off-by: Dimitar Dobrev --- .../Generators/CSharp/CSharpTextTemplate.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 785ba085..e2b76feb 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -899,7 +899,9 @@ namespace CppSharp.Generators.CSharp if (prop.Ignore) continue; PushBlock(CSharpBlockKind.Property); - WriteLine("public {0} {1}", prop.Type, SafeIdentifier(prop.Name)); + WriteLine("{0} {1} {2}", + prop.Access == AccessSpecifier.Public ? "public" : "protected", + prop.Type, SafeIdentifier(prop.Name)); WriteStartBraceIndent(); if (prop.Field != null) @@ -1481,8 +1483,16 @@ namespace CppSharp.Generators.CSharp PushBlock(CSharpBlockKind.Method); GenerateDeclarationCommon(method); - Write(Driver.Options.GenerateAbstractImpls && - @class.IsAbstract && method.IsConstructor ? "protected " : "public "); + switch (method.Access) + { + case AccessSpecifier.Public: + Write(Driver.Options.GenerateAbstractImpls && @class.IsAbstract + && method.IsConstructor ? "protected " : "public "); + break; + case AccessSpecifier.Protected: + Write("protected "); + break; + } if (method.IsVirtual && !method.IsOverride && (!Driver.Options.GenerateAbstractImpls || !method.IsPure)) @@ -1955,7 +1965,8 @@ namespace CppSharp.Generators.CSharp WriteLine("[UnmanagedFunctionPointerAttribute(CallingConvention.{0})]", Helpers.ToCSharpCallConv(functionType.CallingConvention)); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); - WriteLine("public {0};", + WriteLine("{0} {1};", + typedef.Access == AccessSpecifier.Public ? "public" : "protected", string.Format(TypePrinter.VisitDelegate(functionType).Type, SafeIdentifier(typedef.Name))); TypePrinter.PopContext(); From bb14da5a0c700ab0d5eb589a598d08f67570ce2b Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Thu, 5 Sep 2013 00:32:57 +0300 Subject: [PATCH 05/20] Fixed the moving of operators to classes to discard the original name space and function. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/MoveOperatorToClassPass.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Generator/Passes/MoveOperatorToClassPass.cs b/src/Generator/Passes/MoveOperatorToClassPass.cs index c4cdf4d3..bb89b683 100644 --- a/src/Generator/Passes/MoveOperatorToClassPass.cs +++ b/src/Generator/Passes/MoveOperatorToClassPass.cs @@ -29,7 +29,7 @@ namespace CppSharp.Passes var method = new Method() { Namespace = @class, - OriginalNamespace = function.Namespace, + OriginalNamespace = @class, Name = function.Name, OriginalName = function.OriginalName, Mangled = function.Mangled, @@ -41,8 +41,7 @@ namespace CppSharp.Passes IsVariadic = function.IsVariadic, IsInline = function.IsInline, OperatorKind = function.OperatorKind, - SynthKind = FunctionSynthKind.NonMemberOperator, - OriginalFunction = function + SynthKind = FunctionSynthKind.NonMemberOperator }; @class.Methods.Add(method); From 840e3c93cfc4c410b44e843f6483c88ad12a22b3 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 6 Sep 2013 02:37:46 +0300 Subject: [PATCH 06/20] Corrected the access modifier of overridden methods because in C++ overriding may change access. Signed-off-by: Dimitar Dobrev --- src/AST/Class.cs | 16 ++++++++++++++++ src/AST/Function.cs | 13 +++++++++++++ .../Generators/CSharp/CSharpTextTemplate.cs | 16 +++++++++++++++- src/Generator/Utils/ParameterTypeComparer.cs | 18 ------------------ 4 files changed, 44 insertions(+), 19 deletions(-) delete mode 100644 src/Generator/Utils/ParameterTypeComparer.cs diff --git a/src/AST/Class.cs b/src/AST/Class.cs index 9a1d25ab..b1893f71 100644 --- a/src/AST/Class.cs +++ b/src/AST/Class.cs @@ -201,6 +201,22 @@ namespace CppSharp.AST } } + public Method GetRootBaseMethod(Method @override) + { + return (from @base in Bases + let baseMethod = ( + from method in @base.Class.Methods + where + method.Name == @override.Name && + method.ReturnType == @override.ReturnType && + method.Parameters.Count == @override.Parameters.Count && + method.Parameters.SequenceEqual(@override.Parameters, + new ParameterTypeComparer()) + select method).FirstOrDefault() + let rootBaseMethod = @base.Class.GetRootBaseMethod(@override) + select rootBaseMethod ?? baseMethod).FirstOrDefault(); + } + public override T Visit(IDeclVisitor visitor) { return visitor.VisitClassDecl(this); diff --git a/src/AST/Function.cs b/src/AST/Function.cs index 04a20a0a..f922218c 100644 --- a/src/AST/Function.cs +++ b/src/AST/Function.cs @@ -60,6 +60,19 @@ namespace CppSharp.AST } } + public class ParameterTypeComparer : IEqualityComparer + { + public bool Equals(Parameter x, Parameter y) + { + return x.QualifiedType == y.QualifiedType; + } + + public int GetHashCode(Parameter obj) + { + return obj.Type.GetHashCode(); + } + } + public enum FunctionSynthKind { None, diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index e2b76feb..9deb05d9 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -1483,7 +1483,7 @@ namespace CppSharp.Generators.CSharp PushBlock(CSharpBlockKind.Method); GenerateDeclarationCommon(method); - switch (method.Access) + switch (GetValidMethodAccess(method, @class)) { case AccessSpecifier.Public: Write(Driver.Options.GenerateAbstractImpls && @class.IsAbstract @@ -1578,6 +1578,20 @@ namespace CppSharp.Generators.CSharp PopBlock(NewLineKind.BeforeNextBlock); } + private static AccessSpecifier GetValidMethodAccess(Method method, Class @class) + { + switch (method.Access) + { + case AccessSpecifier.Public: + return @class.IsAbstract && method.IsConstructor ? + AccessSpecifier.Protected : AccessSpecifier.Public; + case AccessSpecifier.Protected: + return method.IsOverride ? + @class.GetRootBaseMethod(method).Access : AccessSpecifier.Protected; + } + return AccessSpecifier.Private; + } + private void GenerateVirtualTableFunctionCall(Function method, Class @class) { string delegateId; diff --git a/src/Generator/Utils/ParameterTypeComparer.cs b/src/Generator/Utils/ParameterTypeComparer.cs deleted file mode 100644 index a8740cdc..00000000 --- a/src/Generator/Utils/ParameterTypeComparer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using CppSharp.AST; - -namespace CppSharp.Utils -{ - public class ParameterTypeComparer : IEqualityComparer - { - public bool Equals(Parameter x, Parameter y) - { - return x.QualifiedType == y.QualifiedType; - } - - public int GetHashCode(Parameter obj) - { - return obj.Type.GetHashCode(); - } - } -} From de8b3fc00e1998b54f6b52d8f990c548a6b7e7a3 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sat, 7 Sep 2013 03:16:24 +0300 Subject: [PATCH 07/20] Corrected the checks for private methods because overrides must be allowed through regardless of access. Signed-off-by: Dimitar Dobrev --- src/Generator/AST/Utils.cs | 2 +- .../Generators/CSharp/CSharpTextTemplate.cs | 5 ++--- src/Generator/Passes/CheckIgnoredDecls.cs | 2 +- src/Generator/Passes/GenerateInlinesCodePass.cs | 12 +++++++++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index 40dd92b1..ef905fe2 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -37,7 +37,7 @@ namespace CppSharp.AST if (method.Kind == CXXMethodKind.Conversion) return true; - if (method.Access == AccessSpecifier.Private) + if (method.Access == AccessSpecifier.Private && !method.IsOverride) return true; return false; diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 9deb05d9..2c715c22 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -1585,11 +1585,10 @@ namespace CppSharp.Generators.CSharp case AccessSpecifier.Public: return @class.IsAbstract && method.IsConstructor ? AccessSpecifier.Protected : AccessSpecifier.Public; - case AccessSpecifier.Protected: + default: return method.IsOverride ? - @class.GetRootBaseMethod(method).Access : AccessSpecifier.Protected; + @class.GetRootBaseMethod(method).Access : method.Access; } - return AccessSpecifier.Private; } private void GenerateVirtualTableFunctionCall(Function method, Class @class) diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index fd888e26..e1810b4a 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -109,7 +109,7 @@ namespace CppSharp.Passes if (!VisitDeclaration(method)) return false; - if (method.Access == AccessSpecifier.Private) + if (method.Access == AccessSpecifier.Private && !method.IsOverride) { method.ExplicityIgnored = true; return false; diff --git a/src/Generator/Passes/GenerateInlinesCodePass.cs b/src/Generator/Passes/GenerateInlinesCodePass.cs index b194efa8..28dc0b5b 100644 --- a/src/Generator/Passes/GenerateInlinesCodePass.cs +++ b/src/Generator/Passes/GenerateInlinesCodePass.cs @@ -65,7 +65,7 @@ namespace CppSharp.Passes { string symbol = mangled.Mangled; var declaration = (Declaration) mangled; - if (!declaration.Ignore && declaration.Access != AccessSpecifier.Private && + if (!declaration.Ignore && AccessValid(declaration) && !Driver.LibrarySymbols.FindSymbol(ref symbol) && !currentUnit.FilePath.EndsWith("_impl.h") && !currentUnit.FilePath.EndsWith("_p.h")) @@ -76,5 +76,15 @@ namespace CppSharp.Passes mangledInlines.Add(mangled.Mangled); } } + + private static bool AccessValid(Declaration declaration) + { + if (declaration.Access == AccessSpecifier.Private) + { + var method = declaration as Method; + return method != null && method.IsOverride; + } + return true; + } } } From a15c5b8f996b1e376a521bb27b7ba1540fd96194 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sat, 7 Sep 2013 15:34:37 +0300 Subject: [PATCH 08/20] Fixed the check for ignoring to verify the access at the declaration level. Signed-off-by: Dimitar Dobrev --- src/AST/TranslationUnit.cs | 1 + src/Generator/Passes/CheckIgnoredDecls.cs | 35 +++++++---------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/AST/TranslationUnit.cs b/src/AST/TranslationUnit.cs index ae3574ff..3cd75826 100644 --- a/src/AST/TranslationUnit.cs +++ b/src/AST/TranslationUnit.cs @@ -14,6 +14,7 @@ namespace CppSharp.AST { Macros = new List(); FilePath = file; + Access = AccessSpecifier.Public; } /// Contains the macros present in the unit. diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index e1810b4a..c09bf07f 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -5,15 +5,21 @@ namespace CppSharp.Passes { public class CheckIgnoredDeclsPass : TranslationUnitPass { - public CheckIgnoredDeclsPass() - { - } - public override bool VisitDeclaration(Declaration decl) { if (decl.ExplicityIgnored) return false; + if (decl.Access == AccessSpecifier.Private) + { + Method method = decl as Method; + if (method == null || !method.IsOverride) + { + decl.ExplicityIgnored = true; + return false; + } + } + if (decl.IsDependent) { decl.ExplicityIgnored = true; @@ -24,16 +30,6 @@ namespace CppSharp.Passes return true; } - public override bool VisitClassDecl(Class @class) - { - if (@class.Access == AccessSpecifier.Private) - { - @class.ExplicityIgnored = true; - return false; - } - return base.VisitClassDecl(@class); - } - public override bool VisitFieldDecl(Field field) { if (!VisitDeclaration(field)) @@ -106,16 +102,7 @@ namespace CppSharp.Passes public override bool VisitMethodDecl(Method method) { - if (!VisitDeclaration(method)) - return false; - - if (method.Access == AccessSpecifier.Private && !method.IsOverride) - { - method.ExplicityIgnored = true; - return false; - } - - return base.VisitMethodDecl(method); + return VisitDeclaration(method) && base.VisitMethodDecl(method); } public override bool VisitTypedefDecl(TypedefDecl typedef) From a3bc0491f949454775c03786e818561fd951cc22 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sat, 7 Sep 2013 16:09:42 +0300 Subject: [PATCH 09/20] Assumed types with empty names (that is, "struct { ... };") to be private. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/CleanInvalidDeclNamesPass.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs index d69f42ea..fc2092e8 100644 --- a/src/Generator/Passes/CleanInvalidDeclNamesPass.cs +++ b/src/Generator/Passes/CleanInvalidDeclNamesPass.cs @@ -34,6 +34,13 @@ namespace CppSharp.Passes if (decl is Namespace) return true; + // types with empty names are assumed to be private + if (decl is Class && string.IsNullOrWhiteSpace(decl.Name)) + { + decl.ExplicityIgnored = true; + return false; + } + decl.Name = CheckName(decl.Name); StringHelpers.CleanupText(ref decl.DebugText); From b92897c50e26ca1e682f6656269ae7a946762276 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sat, 7 Sep 2013 17:32:17 +0300 Subject: [PATCH 10/20] Fixed the access of properties generated from fields. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/FieldToPropertyPass.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Generator/Passes/FieldToPropertyPass.cs b/src/Generator/Passes/FieldToPropertyPass.cs index 2997e1d6..a719ea80 100644 --- a/src/Generator/Passes/FieldToPropertyPass.cs +++ b/src/Generator/Passes/FieldToPropertyPass.cs @@ -16,11 +16,12 @@ namespace CppSharp.Passes if (ASTUtils.CheckIgnoreField(field)) return false; - var prop = new Property() + var prop = new Property { Name = field.Name, Namespace = field.Namespace, QualifiedType = field.QualifiedType, + Access = field.Access, Field = field }; @class.Properties.Add(prop); From 2848ee74535ae0e9b4482c06f66c172c23ad2c33 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sun, 8 Sep 2013 00:24:05 +0300 Subject: [PATCH 11/20] Fixed a regression causing a run-time crash with moved operators. Signed-off-by: Dimitar Dobrev --- src/AST/Method.cs | 6 ++++++ .../Passes/CheckOperatorsOverloads.cs | 2 ++ .../Passes/MoveOperatorToClassPass.cs | 21 +++++++------------ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/AST/Method.cs b/src/AST/Method.cs index 74285471..65bbf895 100644 --- a/src/AST/Method.cs +++ b/src/AST/Method.cs @@ -92,6 +92,12 @@ namespace CppSharp.AST Conversion = method.Conversion; } + public Method(Function function) + : base(function) + { + + } + public AccessSpecifierDecl AccessDecl { get; set; } public bool IsVirtual { get; set; } diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index df41f004..964321c8 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -54,6 +54,8 @@ namespace CppSharp.Passes @operator.ExplicityIgnored = true; continue; } + if (@operator.SynthKind == FunctionSynthKind.NonMemberOperator) + continue; // Handle missing operator parameters if (@operator.IsStatic) diff --git a/src/Generator/Passes/MoveOperatorToClassPass.cs b/src/Generator/Passes/MoveOperatorToClassPass.cs index bb89b683..b35753b5 100644 --- a/src/Generator/Passes/MoveOperatorToClassPass.cs +++ b/src/Generator/Passes/MoveOperatorToClassPass.cs @@ -23,27 +23,20 @@ namespace CppSharp.Passes if (!FunctionToInstanceMethodPass.GetClassParameter(param, out @class)) return false; - function.ExplicityIgnored = true; - // Create a new fake method so it acts as a static method. - var method = new Method() + + var method = new Method(function) { Namespace = @class, - OriginalNamespace = @class, - Name = function.Name, - OriginalName = function.OriginalName, - Mangled = function.Mangled, - Access = AccessSpecifier.Public, Kind = CXXMethodKind.Operator, - ReturnType = function.ReturnType, - Parameters = new List(function.Parameters).Skip(1).ToList(), - CallingConvention = function.CallingConvention, - IsVariadic = function.IsVariadic, - IsInline = function.IsInline, OperatorKind = function.OperatorKind, - SynthKind = FunctionSynthKind.NonMemberOperator + SynthKind = FunctionSynthKind.NonMemberOperator, + OriginalFunction = null, + IsStatic = true }; + function.ExplicityIgnored = true; + @class.Methods.Add(method); Driver.Diagnostics.Debug("Function converted to operator: {0}::{1}", From 2f7934569e6036b629fb365318a66f2c2fbaecb9 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sun, 8 Sep 2013 00:50:03 +0300 Subject: [PATCH 12/20] Added tests for overrides changing access and for protected fields. Signed-off-by: Dimitar Dobrev --- tests/Basic/Basic.Tests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 9bc6fc5d..19253e07 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -1,3 +1,4 @@ +using System.Reflection; using NUnit.Framework; using Basic; @@ -95,5 +96,12 @@ public class BasicTests Assert.AreEqual(abstractFoo.pureFunction1(), 10); Assert.AreEqual(abstractFoo.pureFunction2(), 15); } + + [Test] + public void TestPropertyAccessModifier() + { + Assert.That(typeof(Foo2).GetProperty("P", + BindingFlags.Instance | BindingFlags.NonPublic), Is.Not.Null); + } } \ No newline at end of file From 453dc26964e86c11d389d73e117a6642505f9948 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sun, 8 Sep 2013 02:59:51 +0300 Subject: [PATCH 13/20] Fixed the generation of complement operators. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/CheckOperatorsOverloads.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs index 964321c8..0e75f235 100644 --- a/src/Generator/Passes/CheckOperatorsOverloads.cs +++ b/src/Generator/Passes/CheckOperatorsOverloads.cs @@ -86,10 +86,8 @@ namespace CppSharp.Passes var missingKind = CheckMissingOperatorOverloadPair(@class, out index, op1, op2, op.Parameters.Last().Type); - if (missingKind == CXXOperatorKind.None) - return; - - if (op.Ignore) continue; + if (missingKind == CXXOperatorKind.None || op.Ignore) + continue; var method = new Method() { From fddcea040514802bb2cc7879b073d7e01286df71 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Sun, 8 Sep 2013 22:31:11 +0300 Subject: [PATCH 14/20] Fixed the regression caused by methods always returning null regardless of the return type. Signed-off-by: Dimitar Dobrev --- src/Generator/Generators/CSharp/CSharpTextTemplate.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 2c715c22..3bc295c7 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -1779,9 +1779,13 @@ namespace CppSharp.Generators.CSharp var isIntPtr = retTypeName.Contains("IntPtr"); - if (retType.Type.IsPointer() && isIntPtr) + Type pointee; + if (retType.Type.IsPointerTo(out pointee) && isIntPtr) { - string @null = retType.Type.IsPrimitiveType(PrimitiveType.IntPtr) ? + PrimitiveType primitive; + string @null = (pointee.Desugar().IsPrimitiveType(out primitive) || + pointee.Desugar().IsPointer()) && + !CSharpTypePrinter.IsConstCharString(retType) ? "IntPtr.Zero" : "null"; WriteLine("if ({0} == global::System.IntPtr.Zero) return {1};", Generator.GeneratedIdentifier("ret"), @null); From faa32abe20111d1cb1e33a51888c3a8b9c2f176d Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 19:27:41 +0300 Subject: [PATCH 15/20] Ensured the directory to write the C++ file wrapping inlines, exists. Signed-off-by: Dimitar Dobrev --- src/Generator/Passes/GenerateInlinesCodePass.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Generator/Passes/GenerateInlinesCodePass.cs b/src/Generator/Passes/GenerateInlinesCodePass.cs index 28dc0b5b..b75ae572 100644 --- a/src/Generator/Passes/GenerateInlinesCodePass.cs +++ b/src/Generator/Passes/GenerateInlinesCodePass.cs @@ -21,6 +21,7 @@ namespace CppSharp.Passes cppBuilder.AppendFormat("#include \"{0}\"\n", header); var cpp = string.Format("{0}.cpp", Driver.Options.InlinesLibraryName); var path = Path.Combine(Driver.Options.OutputDir, cpp); + Directory.CreateDirectory(Driver.Options.OutputDir); File.WriteAllText(path, cppBuilder.ToString()); switch (Driver.Options.Abi) { From 74ec7308113679117a46ce1ae4f1fe364b66534f Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 19:43:30 +0300 Subject: [PATCH 16/20] Some reordering of code and improved logging. Signed-off-by: Dimitar Dobrev --- src/Generator/Driver.cs | 2 +- src/Generator/Passes/CheckIgnoredDecls.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 936141e9..3bf1e2c1 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -261,7 +261,6 @@ namespace CppSharp public string OutputNamespace; public string OutputDir; public string LibraryName; - private string inlinesLibraryName; public bool OutputInteropIncludes; public bool GenerateLibraryNamespace; public bool GenerateFunctionTemplates; @@ -275,6 +274,7 @@ namespace CppSharp public int MaxIndent; public string CommentPrefix; + private string inlinesLibraryName; public string InlinesLibraryName { get diff --git a/src/Generator/Passes/CheckIgnoredDecls.cs b/src/Generator/Passes/CheckIgnoredDecls.cs index c09bf07f..ea3246ef 100644 --- a/src/Generator/Passes/CheckIgnoredDecls.cs +++ b/src/Generator/Passes/CheckIgnoredDecls.cs @@ -90,7 +90,8 @@ namespace CppSharp.Passes if (retClass == null) { function.ExplicityIgnored = true; - Console.WriteLine("Function '{0}' was ignored due to an indirect return param not of a tag type", + Driver.Diagnostics.EmitWarning( + "Function '{0}' was ignored due to an indirect return param not of a tag type", function.Name); return false; } From 1532f7d0bf046948a2c0c214db4c47046089fd7c Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 19:51:55 +0300 Subject: [PATCH 17/20] Moved the changing of access modifiers of constructors of abstract classes to the pass for internal implementations of abstract classes. Signed-off-by: Dimitar Dobrev --- src/Generator/Generators/CSharp/CSharpTextTemplate.cs | 6 ++---- src/Generator/Passes/GenerateAbstractImplementationsPass.cs | 6 ++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 3bc295c7..3ffdb32c 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -1486,8 +1486,7 @@ namespace CppSharp.Generators.CSharp switch (GetValidMethodAccess(method, @class)) { case AccessSpecifier.Public: - Write(Driver.Options.GenerateAbstractImpls && @class.IsAbstract - && method.IsConstructor ? "protected " : "public "); + Write("public "); break; case AccessSpecifier.Protected: Write("protected "); @@ -1583,8 +1582,7 @@ namespace CppSharp.Generators.CSharp switch (method.Access) { case AccessSpecifier.Public: - return @class.IsAbstract && method.IsConstructor ? - AccessSpecifier.Protected : AccessSpecifier.Public; + return AccessSpecifier.Public; default: return method.IsOverride ? @class.GetRootBaseMethod(method).Access : method.Access; diff --git a/src/Generator/Passes/GenerateAbstractImplementationsPass.cs b/src/Generator/Passes/GenerateAbstractImplementationsPass.cs index 3a614eff..6f17906a 100644 --- a/src/Generator/Passes/GenerateAbstractImplementationsPass.cs +++ b/src/Generator/Passes/GenerateAbstractImplementationsPass.cs @@ -34,7 +34,13 @@ namespace CppSharp.Passes return false; if (@class.IsAbstract) + { + foreach (var ctor in from ctor in @class.Constructors + where ctor.Access == AccessSpecifier.Public + select ctor) + ctor.Access = AccessSpecifier.Protected; internalImpls.Add(AddInternalImplementation(@class)); + } return base.VisitClassDecl(@class); } From 763ce63bca5eff7637f331d17927a520a1bc4214 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 19:59:22 +0300 Subject: [PATCH 18/20] Restored the protected field used to test access modifiers of properties. Signed-off-by: Dimitar Dobrev --- tests/Basic/Basic.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 1ea349f0..487968de 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -25,6 +25,9 @@ public: Foo2 operator<<(signed int i); Foo2 operator<<(signed long l); + +protected: + int P; }; struct DLL_API Bar From 70b4cff9bfda8b5f9b8e0b45ad542c1f9490b61f Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 20:11:35 +0300 Subject: [PATCH 19/20] Broke up the pass for inlines in two main functions. Signed-off-by: Dimitar Dobrev --- .../Passes/GenerateInlinesCodePass.cs | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Generator/Passes/GenerateInlinesCodePass.cs b/src/Generator/Passes/GenerateInlinesCodePass.cs index b75ae572..fb16da61 100644 --- a/src/Generator/Passes/GenerateInlinesCodePass.cs +++ b/src/Generator/Passes/GenerateInlinesCodePass.cs @@ -15,33 +15,45 @@ namespace CppSharp.Passes public override bool VisitLibrary(Library library) { bool result = base.VisitLibrary(library); + Directory.CreateDirectory(Driver.Options.OutputDir); + WriteInlinesIncludes(); + WriteInlinedSymbols(); + return result; + } + + private void WriteInlinesIncludes() + { var cppBuilder = new StringBuilder(); headers.Sort(); foreach (var header in headers) cppBuilder.AppendFormat("#include \"{0}\"\n", header); var cpp = string.Format("{0}.cpp", Driver.Options.InlinesLibraryName); var path = Path.Combine(Driver.Options.OutputDir, cpp); - Directory.CreateDirectory(Driver.Options.OutputDir); File.WriteAllText(path, cppBuilder.ToString()); + } + + private void WriteInlinedSymbols() + { switch (Driver.Options.Abi) { case CppAbi.Microsoft: var defBuilder = new StringBuilder("EXPORTS\r\n"); for (int i = 0; i < mangledInlines.Count; i++) defBuilder.AppendFormat(" {0} @{1}\r\n", - mangledInlines[i], i + 1); - File.WriteAllText(Path.ChangeExtension(path, "def"), - defBuilder.ToString()); + mangledInlines[i], i + 1); + var def = string.Format("{0}.def", Driver.Options.InlinesLibraryName); + File.WriteAllText(Path.Combine(Driver.Options.OutputDir, def), + defBuilder.ToString()); break; default: var symbolsBuilder = new StringBuilder(); foreach (var mangledInline in mangledInlines) symbolsBuilder.AppendFormat("{0}\n", mangledInline); - File.WriteAllText(Path.ChangeExtension(path, "txt"), - symbolsBuilder.ToString()); + var txt = string.Format("{0}.txt", Driver.Options.InlinesLibraryName); + File.WriteAllText(Path.Combine(Driver.Options.OutputDir, txt), + symbolsBuilder.ToString()); break; } - return result; } public override bool VisitTranslationUnit(TranslationUnit unit) From 023389666f3337f287f854bf8296a8e201395704 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 11 Sep 2013 20:50:41 +0300 Subject: [PATCH 20/20] Disabled the test for non-public access in order not to break the build because the C++/CLI back-end does not support protected members yet. Signed-off-by: Dimitar Dobrev --- tests/Basic/Basic.Tests.cs | 2 +- tests/Basic/Basic.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 19253e07..c08ec478 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -97,7 +97,7 @@ public class BasicTests Assert.AreEqual(abstractFoo.pureFunction2(), 15); } - [Test] + [Test, Ignore] public void TestPropertyAccessModifier() { Assert.That(typeof(Foo2).GetProperty("P", diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 487968de..4426f829 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -26,8 +26,9 @@ public: Foo2 operator<<(signed int i); Foo2 operator<<(signed long l); -protected: - int P; + // TODO: uncomment when the C++/CLI back-end supports protected members +//protected: +// int P; }; struct DLL_API Bar