diff --git a/build/Tests.lua b/build/Tests.lua index ac5ace34..b403a7bf 100644 --- a/build/Tests.lua +++ b/build/Tests.lua @@ -38,7 +38,7 @@ function SetupManagedTestProject() SetupManagedProject() end -function SetupTestGeneratorProject(name) +function SetupTestGeneratorProject(name, depends) project(name .. ".Gen") SetupManagedTestProject() kind "ConsoleApp" @@ -47,14 +47,19 @@ function SetupTestGeneratorProject(name) dependson { name .. ".Native" } - links - { + linktable = { "System.Core", "CppSharp.AST", "CppSharp.Generator", - "CppSharp.Generator.Tests" + "CppSharp.Generator.Tests", } + if depends ~= nil then + table.insert(linktable, depends .. ".Gen") + end + + links(linktable) + SetupParser() end @@ -84,7 +89,7 @@ function SetupTestNativeProject(name, depends) files { "**.h", "**.cpp" } if depends ~= nil then - links { depends } + links { depends .. ".Native" } end end @@ -117,7 +122,7 @@ function SetupTestProjectsCSharp(name, depends) linktable = { "CppSharp.Runtime" } if depends ~= nil then - table.insert(linktable, depends) + table.insert(linktable, depends .. ".CSharp") end links(linktable) diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index c015f2e6..1bd72493 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -32,6 +32,18 @@ namespace CppSharp public ASTContext ASTContext { get; private set; } public SymbolContext Symbols { get; private set; } + public struct TranslationUnitRenameInfo + { + public string translationUnit; + public string rootNamespaceName; + } + public static Dictionary RootNamespaceRenames { get; private set; } + + static Driver() + { + Driver.RootNamespaceRenames = new Dictionary(); + } + public Driver(DriverOptions options, IDiagnosticConsumer diagnostics) { Options = options; @@ -279,6 +291,8 @@ namespace CppSharp if (Options.GeneratePropertiesAdvanced) TranslationUnitPasses.AddPass(new GetterSetterToPropertyAdvancedPass()); + + TranslationUnitPasses.AddPass(new RenameRootNamespacesPass()); } public void ProcessCode() diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index b8a52db0..b80de910 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -105,6 +105,43 @@ namespace CppSharp.Generators.CSharp #region Identifiers + // Takes a declaration (type, class etc.) that is referenced from a context, and the context. + // If the referenced name needs a qualification in the context, add it. Otherwise, return just the name. + public string QualifiedIdentifierIfNeeded(Declaration context, Declaration reference) + { + var refNames = new Stack(); + var ctxNames = new Stack(); + + var refCtx = reference; + while (refCtx != null) + { + if (!string.IsNullOrWhiteSpace(refCtx.Name)) + refNames.Push(refCtx.Name); + refCtx = refCtx.Namespace; + } + + var ctxCtx = context; + while (ctxCtx != null) + { + if (!string.IsNullOrWhiteSpace(ctxCtx.Name)) + ctxNames.Push(ctxCtx.Name); + ctxCtx = ctxCtx.Namespace; + } + + if (context.GenerationKind == GenerationKind.Generate && Options.GenerateLibraryNamespace) + ctxNames.Push(Options.OutputNamespace); + if (reference.GenerationKind == GenerationKind.Generate && Options.GenerateLibraryNamespace) + refNames.Push(Options.OutputNamespace); + + while (refNames.Count > 1 && ctxNames.Count > 1 &&refNames.Peek() == ctxNames.Peek()) + { + refNames.Pop(); + ctxNames.Pop(); + } + + return string.Join(".", refNames); + } + public string QualifiedIdentifier(Declaration decl) { var names = new List { decl.Name }; @@ -633,7 +670,7 @@ namespace CppSharp.Generators.CSharp bases.AddRange( from @base in @class.Bases where @base.IsClass - select QualifiedIdentifier(@base.Class)); + select QualifiedIdentifierIfNeeded(@class, @base.Class)); } if (@class.IsGenerated) @@ -1781,7 +1818,7 @@ namespace CppSharp.Generators.CSharp var hasBaseClass = @class.HasBaseClass && @class.BaseClass.IsRefType; if (hasBaseClass) WriteLineIndent(": base(({0}.Internal*) native{1})", - @class.BaseClass.Name, @class.IsAbstractImpl ? ", true" : string.Empty); + QualifiedIdentifierIfNeeded(@class, @class.BaseClass), @class.IsAbstractImpl ? ", true" : string.Empty); WriteStartBraceIndent(); @@ -1828,7 +1865,7 @@ namespace CppSharp.Generators.CSharp // Allocate memory for a new native object and call the ctor. WriteLine("var ret = Marshal.AllocHGlobal({0});", @class.Layout.Size); WriteLine("{0}.Internal.{1}(ret, new global::System.IntPtr(&native));", - QualifiedIdentifier(@class), GetFunctionNativeIdentifier(copyCtorMethod)); + QualifiedIdentifierIfNeeded(@class, @class), GetFunctionNativeIdentifier(copyCtorMethod)); WriteLine("return ({0}.Internal*) ret;", className); } else @@ -2243,7 +2280,7 @@ namespace CppSharp.Generators.CSharp if (construct == null) { WriteLine("var {0} = new {1}.Internal();", GeneratedIdentifier("ret"), - QualifiedIdentifier(retClass.OriginalClass ?? retClass)); + QualifiedIdentifierIfNeeded(function, retClass.OriginalClass ?? retClass)); } else { diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index b3a85263..7897768d 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -551,9 +551,6 @@ namespace CppSharp.Generators.CSharp var ctx = decl.Namespace; while (ctx != null) { - if (ctx is TranslationUnit) - break; - if (!string.IsNullOrWhiteSpace(ctx.Name)) names.Add(ctx.Name); diff --git a/src/Generator/Passes/RenameRootNamespaces.cs b/src/Generator/Passes/RenameRootNamespaces.cs new file mode 100644 index 00000000..565bcfd2 --- /dev/null +++ b/src/Generator/Passes/RenameRootNamespaces.cs @@ -0,0 +1,39 @@ +using CppSharp.AST; +using System; +using System.Collections.Generic; + +namespace CppSharp.Passes +{ + // This pass visits all the translation units and checks if they originate from library being processed or + // from some other library that is being depended upon. It will rename the root namespaces of all the "foreign" + // libraries so that there wouldn't be clashes and so that the code generation phase would be able to generate + // names with fully qualified namespace prefixes. + public class RenameRootNamespacesPass : TranslationUnitPass + { + + public override bool VisitTranslationUnit(TranslationUnit unit) + { + if (!base.VisitTranslationUnit(unit)) + return false; + + + var fileName = unit.TranslationUnit.FileName; + if (Driver.RootNamespaceRenames.ContainsKey(fileName)) + { + var rootNamespace = Driver.RootNamespaceRenames[fileName].rootNamespaceName; + if (this.Driver.Options.OutputNamespace != rootNamespace) + unit.Name = rootNamespace; + } + else if (unit.GenerationKind == GenerationKind.Generate) + { + Driver.RootNamespaceRenames.Add(fileName, new Driver.TranslationUnitRenameInfo + { + translationUnit = fileName, + rootNamespaceName = Driver.Options.OutputNamespace, + }); + } + return true; + } + + } +} \ No newline at end of file diff --git a/tests/NamespacesBase/NamespacesBase.cpp b/tests/NamespacesBase/NamespacesBase.cpp index 07685d46..a91800f2 100644 --- a/tests/NamespacesBase/NamespacesBase.cpp +++ b/tests/NamespacesBase/NamespacesBase.cpp @@ -10,4 +10,4 @@ Base::Base(int i) Base::Base() { -} \ No newline at end of file +} diff --git a/tests/NamespacesBase/NamespacesBase.cs b/tests/NamespacesBase/NamespacesBase.cs index 871a4204..d274bb12 100644 --- a/tests/NamespacesBase/NamespacesBase.cs +++ b/tests/NamespacesBase/NamespacesBase.cs @@ -32,7 +32,5 @@ namespace CppSharp.Tests { ConsoleDriver.Run(new NamespacesBaseTests(GeneratorKind.CSharp)); } - } } - diff --git a/tests/NamespacesBase/NamespacesBase.h b/tests/NamespacesBase/NamespacesBase.h index b431de6c..0caa7020 100644 --- a/tests/NamespacesBase/NamespacesBase.h +++ b/tests/NamespacesBase/NamespacesBase.h @@ -1,5 +1,28 @@ #include "../Tests.h" + +namespace OverlappingNamespace +{ + enum ColorsEnum { + white, + black, + red, + blue, + green, + }; + + class InBaseLib + { + public: + InBaseLib() + { + + }; + }; +} + + + class DLL_API Base { public: @@ -8,4 +31,4 @@ public: private: int b; -}; \ No newline at end of file +}; diff --git a/tests/NamespacesDerived/NamespacesDerived.cpp b/tests/NamespacesDerived/NamespacesDerived.cpp index 4bb67564..88c00324 100644 --- a/tests/NamespacesDerived/NamespacesDerived.cpp +++ b/tests/NamespacesDerived/NamespacesDerived.cpp @@ -1,6 +1,60 @@ #include "NamespacesDerived.h" -Derived::Derived() : Base(10), component(5) +OverlappingNamespace::InDerivedLib::InDerivedLib() : parentNSComponent(), color(black) { } + +Derived::Derived() : Base(10), baseComponent(5), nestedNSComponent(), color(OverlappingNamespace::blue) +{ +} + +Base Derived::getBase() +{ + return baseComponent; +} + +void Derived::setBase(Base b) +{ + baseComponent = b; +} + +OverlappingNamespace::InBaseLib Derived::getNestedNSComponent() +{ + return nestedNSComponent; +} + +void Derived::setNestedNSComponent(OverlappingNamespace::InBaseLib c) +{ + nestedNSComponent = c; +} + + +Base2::Base2() +{ +} + + +Derived2::Derived2() : Base2() +{ +} + +Base2 Derived2::getBase() +{ + return baseComponent; +} + +void Derived2::setBase(Base2 b) +{ + baseComponent = b; +} + +OverlappingNamespace::InDerivedLib Derived2::getNestedNSComponent() +{ + return nestedNSComponent; +} + +void Derived2::setNestedNSComponent(OverlappingNamespace::InDerivedLib c) +{ + nestedNSComponent = c; +} diff --git a/tests/NamespacesDerived/NamespacesDerived.cs b/tests/NamespacesDerived/NamespacesDerived.cs index c9f49ffe..8addbe3a 100644 --- a/tests/NamespacesDerived/NamespacesDerived.cs +++ b/tests/NamespacesDerived/NamespacesDerived.cs @@ -15,7 +15,6 @@ namespace CppSharp.Tests public override void SetupPasses(Driver driver) { - driver.Options.DependentNameSpaces.Add("NamespacesBase"); } public override void Preprocess(Driver driver, ASTContext ctx) @@ -39,6 +38,7 @@ namespace CppSharp.Tests public static void Main(string[] args) { + ConsoleDriver.Run(new NamespacesBaseTests(GeneratorKind.CSharp)); ConsoleDriver.Run(new NamespacesDerivedTests(GeneratorKind.CSharp)); } diff --git a/tests/NamespacesDerived/NamespacesDerived.h b/tests/NamespacesDerived/NamespacesDerived.h index 091fb7c4..5f4d5287 100644 --- a/tests/NamespacesDerived/NamespacesDerived.h +++ b/tests/NamespacesDerived/NamespacesDerived.h @@ -1,13 +1,60 @@ #include "../Tests.h" #include "../NamespacesBase/NamespacesBase.h" +// Namespace clashes with NamespacesBase.OverlappingNamespace +// Test whether qualified names turn out right. +namespace OverlappingNamespace +{ + + class InDerivedLib + { + public: + InDerivedLib(); + Base parentNSComponent; + ColorsEnum color; + }; +} + + +// Using a type imported from a different library. class DLL_API Derived : public Base { public: Derived(); - Base component; + Base baseComponent; + Base getBase(); + void setBase(Base); + + OverlappingNamespace::InBaseLib nestedNSComponent; + OverlappingNamespace::InBaseLib getNestedNSComponent(); + void setNestedNSComponent(OverlappingNamespace::InBaseLib); + + OverlappingNamespace::ColorsEnum color; private: int d; -}; \ No newline at end of file +}; + + +// For reference: using a type derived in the same library +class Base2 +{ +public: + Base2(); +}; + +class Derived2 : public Base2 +{ +public: + Derived2(); + + Base2 baseComponent; + Base2 getBase(); + void setBase(Base2); + + OverlappingNamespace::InDerivedLib nestedNSComponent; + OverlappingNamespace::InDerivedLib getNestedNSComponent(); + void setNestedNSComponent(OverlappingNamespace::InDerivedLib); + +}; diff --git a/tests/NamespacesDerived/premake4.lua b/tests/NamespacesDerived/premake4.lua index 0056d5f6..ad98cb93 100644 --- a/tests/NamespacesDerived/premake4.lua +++ b/tests/NamespacesDerived/premake4.lua @@ -1,4 +1,4 @@ group "Tests/Namespaces" - SetupTestGeneratorProject("NamespacesDerived") - SetupTestNativeProject("NamespacesDerived", "NamespacesBase.Native") - SetupTestProjectsCSharp("NamespacesDerived", "NamespacesBase.CSharp") \ No newline at end of file + SetupTestGeneratorProject("NamespacesDerived", "NamespacesBase") + SetupTestNativeProject("NamespacesDerived", "NamespacesBase") + SetupTestProjectsCSharp("NamespacesDerived", "NamespacesBase") \ No newline at end of file