From bea0c7b59d4dfcf7290a4b72428e1b7848d337cd Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Wed, 6 Mar 2019 17:34:28 +0200 Subject: [PATCH] Move non-scoped enums nested in classes to their parents Signed-off-by: Dimitar Dobrev --- src/AST/Declaration.cs | 8 ++- src/Generator/Driver.cs | 1 + .../MoveNonScopedNestedEnumsToParentPass.cs | 56 +++++++++++++++++++ tests/CSharp/CSharp.Tests.cs | 18 +++--- tests/Common/Common.Tests.cs | 13 +++-- tests/Common/Common.cpp | 10 ++++ tests/Common/Common.h | 11 +++- 7 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 src/Generator/Passes/MoveNonScopedNestedEnumsToParentPass.cs diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index 39bb09619b..bcf609a44c 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -201,13 +201,15 @@ public virtual string LogicalOriginalName public string GetQualifiedName(Func getName, Func getNamespace) { - if (Namespace == null) + DeclarationContext declarationContext = getNamespace(this); + + if (declarationContext == null) return getName(this); - if (Namespace.IsRoot) + if (declarationContext.IsRoot) return getName(this); - var namespaces = GatherNamespaces(getNamespace(this)); + var namespaces = GatherNamespaces(declarationContext); var names = namespaces.Select(getName).ToList(); names.Add(getName(this)); diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index e33940c7b3..11eddfc390 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -235,6 +235,7 @@ public void SetupPasses(ILibrary library) TranslationUnitPasses.AddPass(new FindSymbolsPass()); TranslationUnitPasses.AddPass(new CheckMacroPass()); TranslationUnitPasses.AddPass(new CheckStaticClass()); + TranslationUnitPasses.AddPass(new MoveNonScopedNestedEnumsToParentPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); diff --git a/src/Generator/Passes/MoveNonScopedNestedEnumsToParentPass.cs b/src/Generator/Passes/MoveNonScopedNestedEnumsToParentPass.cs new file mode 100644 index 0000000000..11b50061c7 --- /dev/null +++ b/src/Generator/Passes/MoveNonScopedNestedEnumsToParentPass.cs @@ -0,0 +1,56 @@ +using CppSharp.AST; +using System.Collections.Generic; +using System.Linq; + +namespace CppSharp.Passes +{ + /// + /// This pass moves old-style (non-scoped) enumerations nested in classes + /// to the parents of those classes. + /// + /// + /// Such enums are presumably written this way because C++ before 11 + /// could not scope enums and nesting was the only way to do so + /// in order to prevent conflicts. But target languages don't have + /// this limitation so we can generate a more sensible API. + /// + public class MoveNonScopedNestedEnumsToParentPass : TranslationUnitPass + { + public override bool VisitASTContext(ASTContext context) + { + bool result = base.VisitASTContext(context); + + foreach (var movableEnum in movableEnums) + { + DeclarationContext declarationContext = movableEnum.Namespace; + declarationContext.Declarations.Remove(movableEnum); + declarationContext.Namespace.Declarations.Add(movableEnum); + movableEnum.Namespace = declarationContext.Namespace; + } + + return result; + } + + public override bool VisitEnumDecl(Enumeration @enum) + { + if (!base.VisitEnumDecl(@enum)) + return false; + + if (string.IsNullOrEmpty(@enum.OriginalName) || + !(@enum.Namespace is Class) || + @enum.Access != AccessSpecifier.Public || + @enum.IsScoped) + return false; + + if (@enum.Namespace.Namespace.Declarations.Union(movableEnums).Any( + e => e.OriginalName == @enum.OriginalName)) + return false; + + movableEnums.Add(@enum); + + return true; + } + + private readonly List movableEnums = new List(); + } +} diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/CSharp/CSharp.Tests.cs index 12cea5249e..8984dbbaff 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/CSharp/CSharp.Tests.cs @@ -38,10 +38,10 @@ public void TestUncompilableCode() new HasCtorWithMappedToEnum(TestFlag.Flag1).Dispose(); using (var testOverrideFromSecondaryBase = new TestOverrideFromSecondaryBase()) { - testOverrideFromSecondaryBase.function(); + testOverrideFromSecondaryBase.Function(); var ok = false; - testOverrideFromSecondaryBase.function(ref ok); - var property = testOverrideFromSecondaryBase.property; + testOverrideFromSecondaryBase.Function(ref ok); + var property = testOverrideFromSecondaryBase.Property; testOverrideFromSecondaryBase.VirtualMember(); } using (var foo = new Foo()) @@ -670,12 +670,12 @@ public void TestEnumProperty() { using (var proprietor = new Proprietor()) { - Assert.That(proprietor.Items, Is.EqualTo(Bar.Items.Item1)); - proprietor.Items = Bar.Items.Item2; - Assert.That(proprietor.Items, Is.EqualTo(Bar.Items.Item2)); - Assert.That(proprietor.ItemsByValue, Is.EqualTo(Bar.Items.Item1)); - proprietor.ItemsByValue = Bar.Items.Item2; - Assert.That(proprietor.ItemsByValue, Is.EqualTo(Bar.Items.Item2)); + Assert.That(proprietor.Items, Is.EqualTo(Items.Item1)); + proprietor.Items = Items.Item2; + Assert.That(proprietor.Items, Is.EqualTo(Items.Item2)); + Assert.That(proprietor.ItemsByValue, Is.EqualTo(Items.Item1)); + proprietor.ItemsByValue = Items.Item2; + Assert.That(proprietor.ItemsByValue, Is.EqualTo(Items.Item2)); } } diff --git a/tests/Common/Common.Tests.cs b/tests/Common/Common.Tests.cs index 75b6c372d7..cecad3c3c5 100644 --- a/tests/Common/Common.Tests.cs +++ b/tests/Common/Common.Tests.cs @@ -23,7 +23,7 @@ public unsafe void TestCodeGeneration() using (var foo = new Foo()) { Bar bar = foo; - Assert.IsTrue(Bar.Item.Item1 == bar); + Assert.IsTrue(Item.Item1 == bar); using (var hasOverloadsWithDifferentPointerKindsToSameType = new HasOverloadsWithDifferentPointerKindsToSameType()) @@ -101,7 +101,7 @@ public void TestHello() var bar = new Bar { A = 4, B = 7 }; Assert.That(hello.AddBar(bar), Is.EqualTo(11)); - Assert.That(bar.RetItem1(), Is.EqualTo(Bar.Item.Item1)); + Assert.That(bar.RetItem1(), Is.EqualTo(Item.Item1)); var retFoo = hello.RetFoo(7, 2.0f); Assert.That(retFoo.A, Is.EqualTo(7)); @@ -245,7 +245,7 @@ public void TestLeftShiftOperator() { var foo2 = new Foo2 { C = 2 }; Foo2 result = foo2 << 3; - foo2.TestKeywordParam(IntPtr.Zero, Bar.Item.Item1, 1); + foo2.TestKeywordParam(IntPtr.Zero, Item.Item1, 1); Assert.That(result.C, Is.EqualTo(16)); } @@ -501,8 +501,11 @@ public void TestProperties() prop.VirtualSetterReturnsBoolean = 45; Assert.That(prop.VirtualSetterReturnsBoolean, Is.EqualTo(45)); - Assert.That(prop.nestedEnum(), Is.EqualTo(5)); - Assert.That(prop.nestedEnum(55), Is.EqualTo(55)); + Assert.That(prop.NestedEnum(), Is.EqualTo(5)); + Assert.That(prop.NestedEnum(55), Is.EqualTo(55)); + + Assert.That(prop.nestedScopedEnum(10), Is.EqualTo(10)); + Assert.That(prop.nestedScopedEnum(65), Is.EqualTo(65)); } } diff --git a/tests/Common/Common.cpp b/tests/Common/Common.cpp index 862d8d6ac1..c20a1191bf 100644 --- a/tests/Common/Common.cpp +++ b/tests/Common/Common.cpp @@ -596,6 +596,16 @@ int TestProperties::nestedEnum(int i) return i; } +int TestProperties::nestedScopedEnum() +{ + return 10; +} + +int TestProperties::nestedScopedEnum(int i) +{ + return i; +} + HasOverridenSetter::HasOverridenSetter() { } diff --git a/tests/Common/Common.h b/tests/Common/Common.h index 9aa5236c0a..ebfde7d1f9 100644 --- a/tests/Common/Common.h +++ b/tests/Common/Common.h @@ -578,7 +578,13 @@ DLL_API int Function() struct DLL_API TestProperties { public: - enum class NestedEnum + enum NestedEnum + { + Value1, + Value2 + }; + + enum class NestedScopedEnum { Value1, Value2 @@ -609,6 +615,9 @@ struct DLL_API TestProperties int nestedEnum(); int nestedEnum(int i); + + int nestedScopedEnum(); + int nestedScopedEnum(int i); private: int FieldValue; double _refToPrimitiveInSetter;