From 71d9da073358efb83534946e5a7b8a904cb12361 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 12 Nov 2013 19:13:32 +0200 Subject: [PATCH 1/3] Used LINQ to simplify the searching. Signed-off-by: Dimitar Dobrev --- src/AST/ASTContext.cs | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/src/AST/ASTContext.cs b/src/AST/ASTContext.cs index a6e895bb..64d8ad14 100644 --- a/src/AST/ASTContext.cs +++ b/src/AST/ASTContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace CppSharp.AST { @@ -50,61 +51,37 @@ namespace CppSharp.AST /// Finds an existing enum in the library modules. public IEnumerable FindEnum(string name) { - foreach (var module in TranslationUnits) - { - var type = module.FindEnum(name); - if (type != null) yield return type; - } + return TranslationUnits.Select(module => module.FindEnum(name)).Where(type => type != null); } /// Finds the complete declaration of an enum. public Enumeration FindCompleteEnum(string name) { - foreach (var @enum in FindEnum(name)) - if (!@enum.IsIncomplete) - return @enum; - - return null; + return FindEnum(name).FirstOrDefault(@enum => !@enum.IsIncomplete); } /// Finds an existing struct/class in the library modules. public IEnumerable FindClass(string name, bool create = false) { - foreach (var module in TranslationUnits) - { - var type = module.FindClass(name); - if (type != null) yield return type; - } + return TranslationUnits.Select(module => module.FindClass(name)).Where(type => type != null); } /// Finds the complete declaration of a class. public Class FindCompleteClass(string name) { - foreach (var @class in FindClass(name)) - if (!@class.IsIncomplete) - return @class; - - return null; + return FindClass(name).FirstOrDefault(@class => !@class.IsIncomplete); } /// Finds an existing function in the library modules. public IEnumerable FindFunction(string name) { - foreach (var module in TranslationUnits) - { - var type = module.FindFunction(name); - if (type != null) yield return type; - } + return TranslationUnits.Select(module => module.FindFunction(name)).Where(type => type != null); } /// Finds an existing typedef in the library modules. public IEnumerable FindTypedef(string name) { - foreach (var module in TranslationUnits) - { - var type = module.FindTypedef(name); - if (type != null) yield return type; - } + return TranslationUnits.Select(module => module.FindTypedef(name)).Where(type => type != null); } /// Finds an existing declaration by name. From 1473488289556509ee82bd79785201a92ed0a6e8 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 12 Nov 2013 19:34:23 +0200 Subject: [PATCH 2/3] Added a pass to move functions to an appropriate existing class if possible. Signed-off-by: Dimitar Dobrev --- src/AST/ASTContext.cs | 16 +++--- src/AST/Namespace.cs | 10 ++-- .../Passes/MoveFunctionToClassPass.cs | 49 +++++++++++++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/Generator/Passes/MoveFunctionToClassPass.cs diff --git a/src/AST/ASTContext.cs b/src/AST/ASTContext.cs index 64d8ad14..656d6d1b 100644 --- a/src/AST/ASTContext.cs +++ b/src/AST/ASTContext.cs @@ -61,27 +61,31 @@ namespace CppSharp.AST } /// Finds an existing struct/class in the library modules. - public IEnumerable FindClass(string name, bool create = false) + public IEnumerable FindClass(string name, bool create = false, bool ignoreCase = false) { - return TranslationUnits.Select(module => module.FindClass(name)).Where(type => type != null); + return TranslationUnits.Select( + module => module.FindClass(name, ignoreCase)).Where(type => type != null); } /// Finds the complete declaration of a class. - public Class FindCompleteClass(string name) + public Class FindCompleteClass(string name, bool ignoreCase = false) { - return FindClass(name).FirstOrDefault(@class => !@class.IsIncomplete); + return FindClass(name, ignoreCase: ignoreCase).FirstOrDefault( + @class => !@class.IsIncomplete); } /// Finds an existing function in the library modules. public IEnumerable FindFunction(string name) { - return TranslationUnits.Select(module => module.FindFunction(name)).Where(type => type != null); + return TranslationUnits.Select(module => module.FindFunction(name)).Where( + type => type != null); } /// Finds an existing typedef in the library modules. public IEnumerable FindTypedef(string name) { - return TranslationUnits.Select(module => module.FindTypedef(name)).Where(type => type != null); + return TranslationUnits.Select(module => module.FindTypedef(name)).Where( + type => type != null); } /// Finds an existing declaration by name. diff --git a/src/AST/Namespace.cs b/src/AST/Namespace.cs index 64c77d1d..cf9d2037 100644 --- a/src/AST/Namespace.cs +++ b/src/AST/Namespace.cs @@ -168,16 +168,20 @@ namespace CppSharp.AST return @class; } - public Class FindClass(string name) + public Class FindClass(string name, bool ignoreCase = false) { if (string.IsNullOrEmpty(name)) return null; - var entries = name.Split(new string[] { "::" }, + var entries = name.Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries).ToList(); if (entries.Count <= 1) { - var @class = Classes.Find(e => e.Name.Equals(name)); + Class @class; + if (ignoreCase) + @class = Classes.Find(e => e.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + else + @class = Classes.Find(e => e.Name.Equals(name)); return @class; } diff --git a/src/Generator/Passes/MoveFunctionToClassPass.cs b/src/Generator/Passes/MoveFunctionToClassPass.cs new file mode 100644 index 00000000..ead334a2 --- /dev/null +++ b/src/Generator/Passes/MoveFunctionToClassPass.cs @@ -0,0 +1,49 @@ +using System.Linq; +using CppSharp.AST; + +namespace CppSharp.Passes +{ + public class MoveFunctionToClassPass : TranslationUnitPass + { + public override bool VisitFunctionDecl(Function function) + { + if (!AlreadyVisited(function) && !function.Ignore && !(function.Namespace is Class) + // HACK: there are bugs with operators generated by Q_DECLARE_OPERATORS_FOR_FLAGS, an incorrect argument type, to say the least + && !function.IsOperator) + { + TranslationUnit unit = function.Namespace as TranslationUnit; + Class @class; + if (unit != null) + { + @class = Driver.ASTContext.FindCompleteClass( + unit.FileNameWithoutExtension.ToLowerInvariant(), true); + if (@class != null) + { + MoveFunction(function, @class); + return base.VisitFunctionDecl(function); + } + } + @class = Driver.ASTContext.FindClass( + function.Namespace.Name, ignoreCase: true).FirstOrDefault(); + if (@class != null) + { + MoveFunction(function, @class); + } + } + return base.VisitFunctionDecl(function); + } + + private static void MoveFunction(Function function, Class @class) + { + var method = new Method(function) + { + Namespace = @class, + IsStatic = true + }; + + function.ExplicityIgnored = true; + + @class.Methods.Add(method); + } + } +} From 3cf6c7b3f16262ec4ca750b9e8def83eb85e014b Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 13 Nov 2013 00:31:05 +0200 Subject: [PATCH 3/3] Added a test for the pass that moves functions to a class. Signed-off-by: Dimitar Dobrev --- src/AST/ASTContext.cs | 18 ++++--- src/AST/Namespace.cs | 10 ++-- src/Generator/Driver.cs | 1 + .../Passes/MoveFunctionToClassPass.cs | 53 +++++++++++-------- tests/Basic/Basic.Tests.cs | 6 +++ tests/Basic/Basic.cpp | 5 ++ tests/Basic/Basic.h | 7 +++ 7 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/AST/ASTContext.cs b/src/AST/ASTContext.cs index 656d6d1b..8ad4c139 100644 --- a/src/AST/ASTContext.cs +++ b/src/AST/ASTContext.cs @@ -51,7 +51,8 @@ namespace CppSharp.AST /// Finds an existing enum in the library modules. public IEnumerable FindEnum(string name) { - return TranslationUnits.Select(module => module.FindEnum(name)).Where(type => type != null); + return TranslationUnits.Select( + module => module.FindEnum(name)).Where(type => type != null); } /// Finds the complete declaration of an enum. @@ -61,10 +62,13 @@ namespace CppSharp.AST } /// Finds an existing struct/class in the library modules. - public IEnumerable FindClass(string name, bool create = false, bool ignoreCase = false) + public IEnumerable FindClass(string name, bool create = false, + bool ignoreCase = false) { return TranslationUnits.Select( - module => module.FindClass(name, ignoreCase)).Where(type => type != null); + module => module.FindClass(name, + ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) + .Where(type => type != null); } /// Finds the complete declaration of a class. @@ -77,15 +81,15 @@ namespace CppSharp.AST /// Finds an existing function in the library modules. public IEnumerable FindFunction(string name) { - return TranslationUnits.Select(module => module.FindFunction(name)).Where( - type => type != null); + return TranslationUnits.Select(module => module.FindFunction(name)) + .Where(type => type != null); } /// Finds an existing typedef in the library modules. public IEnumerable FindTypedef(string name) { - return TranslationUnits.Select(module => module.FindTypedef(name)).Where( - type => type != null); + return TranslationUnits.Select(module => module.FindTypedef(name)) + .Where(type => type != null); } /// Finds an existing declaration by name. diff --git a/src/AST/Namespace.cs b/src/AST/Namespace.cs index cf9d2037..4d29d693 100644 --- a/src/AST/Namespace.cs +++ b/src/AST/Namespace.cs @@ -168,7 +168,8 @@ namespace CppSharp.AST return @class; } - public Class FindClass(string name, bool ignoreCase = false) + public Class FindClass(string name, + StringComparison stringComparison = StringComparison.Ordinal) { if (string.IsNullOrEmpty(name)) return null; @@ -177,12 +178,7 @@ namespace CppSharp.AST if (entries.Count <= 1) { - Class @class; - if (ignoreCase) - @class = Classes.Find(e => e.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); - else - @class = Classes.Find(e => e.Name.Equals(name)); - return @class; + return Classes.Find(e => e.Name.Equals(name, stringComparison)); } var className = entries[entries.Count - 1]; diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 728b828a..5e78bfc9 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -201,6 +201,7 @@ namespace CppSharp TranslationUnitPasses.AddPass(new FindSymbolsPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); + TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass()); TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance()); diff --git a/src/Generator/Passes/MoveFunctionToClassPass.cs b/src/Generator/Passes/MoveFunctionToClassPass.cs index ead334a2..e09d6a70 100644 --- a/src/Generator/Passes/MoveFunctionToClassPass.cs +++ b/src/Generator/Passes/MoveFunctionToClassPass.cs @@ -3,36 +3,36 @@ using CppSharp.AST; namespace CppSharp.Passes { + /// + /// Moves a function to a class, if any, named after the function's header. + /// public class MoveFunctionToClassPass : TranslationUnitPass { public override bool VisitFunctionDecl(Function function) { - if (!AlreadyVisited(function) && !function.Ignore && !(function.Namespace is Class) - // HACK: there are bugs with operators generated by Q_DECLARE_OPERATORS_FOR_FLAGS, an incorrect argument type, to say the least - && !function.IsOperator) + if (AlreadyVisited(function) || function.Ignore || function.Namespace is Class) + return base.VisitFunctionDecl(function); + + Class @class = FindClassToMoveFunctionTo(function.Namespace); + if (@class != null) { - TranslationUnit unit = function.Namespace as TranslationUnit; - Class @class; - if (unit != null) - { - @class = Driver.ASTContext.FindCompleteClass( - unit.FileNameWithoutExtension.ToLowerInvariant(), true); - if (@class != null) - { - MoveFunction(function, @class); - return base.VisitFunctionDecl(function); - } - } - @class = Driver.ASTContext.FindClass( - function.Namespace.Name, ignoreCase: true).FirstOrDefault(); - if (@class != null) - { - MoveFunction(function, @class); - } + MoveFunction(function, @class); } return base.VisitFunctionDecl(function); } + private Class FindClassToMoveFunctionTo(INamedDecl @namespace) + { + TranslationUnit unit = @namespace as TranslationUnit; + if (unit == null) + { + return Driver.ASTContext.FindClass( + @namespace.Name, ignoreCase: true).FirstOrDefault(); + } + return Driver.ASTContext.FindCompleteClass( + unit.FileNameWithoutExtension.ToLowerInvariant(), true); + } + private static void MoveFunction(Function function, Class @class) { var method = new Method(function) @@ -41,6 +41,17 @@ namespace CppSharp.Passes IsStatic = true }; + if (method.OperatorKind != CXXOperatorKind.None) + { + var param = function.Parameters[0]; + Class type; + if (!FunctionToInstanceMethodPass.GetClassParameter(param, out type)) + return; + method.Kind = CXXMethodKind.Operator; + method.SynthKind = FunctionSynthKind.NonMemberOperator; + method.OriginalFunction = null; + } + function.ExplicityIgnored = true; @class.Methods.Add(method); diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 2b22b1d7..7c51786e 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -123,6 +123,12 @@ public class BasicTests Assert.That(foo.GetANSI(), Is.EqualTo("ANSI")); } + [Test] + public void TestMoveFunctionToClass() + { + Assert.That(basic.test(new basic()), Is.EqualTo(5)); + } + [Test, Ignore] public void TestConversionOperator() { diff --git a/tests/Basic/Basic.cpp b/tests/Basic/Basic.cpp index 056e1dd4..b7df47d6 100644 --- a/tests/Basic/Basic.cpp +++ b/tests/Basic/Basic.cpp @@ -203,3 +203,8 @@ void DefaultParameters::Bar() const void DefaultParameters::Bar() { } + +int test(basic& s) +{ + return 5; +} diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 47436670..7296ce01 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -178,3 +178,10 @@ class Base class Derived : public Base { }; + +class DLL_API basic +{ + +}; + +DLL_API int test(basic& s);