diff --git a/src/AST/Namespace.cs b/src/AST/Namespace.cs index 98d2d7c0..48566673 100644 --- a/src/AST/Namespace.cs +++ b/src/AST/Namespace.cs @@ -19,6 +19,7 @@ namespace CppSharp.AST public List Typedefs; public List Variables; public List Events; + public List TypeReferences; // Used to keep track of anonymous declarations. public Dictionary Anonymous; @@ -44,9 +45,27 @@ namespace CppSharp.AST Typedefs = new List(); Variables = new List(); Events = new List(); + TypeReferences = new List(); Anonymous = new Dictionary(); } + public IEnumerable GatherParentNamespaces() + { + var children = new List(); + var currentNamespace = this; + + while (currentNamespace != null) + { + if (!(currentNamespace is TranslationUnit)) + children.Add(currentNamespace); + + currentNamespace = currentNamespace.Namespace; + } + + children.Reverse(); + return children; + } + public Declaration FindAnonymous(ulong key) { return Anonymous.ContainsKey(key) ? Anonymous[key] : null; diff --git a/src/AST/TranslationUnit.cs b/src/AST/TranslationUnit.cs index 3cd75826..d027eb7c 100644 --- a/src/AST/TranslationUnit.cs +++ b/src/AST/TranslationUnit.cs @@ -57,8 +57,5 @@ namespace CppSharp.AST /// Contains the include path. public string IncludePath; - - /// Type references object. - public object TypeReferences; } } \ No newline at end of file diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 2cc99e78..36715061 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -30,13 +30,18 @@ namespace CppSharp.Generators.CLI if (Options.OutputInteropIncludes) WriteLine("#include \"CppSharp.h\""); + // Generate #include forward references. PushBlock(CLIBlockKind.IncludesForwardReferences); WriteLine("#include <{0}>", TranslationUnit.IncludePath); GenerateIncludeForwardRefs(); PopBlock(NewLineKind.BeforeNextBlock); - PopBlock(NewLineKind.Always); + // Generate namespace for forward references. + PushBlock(CLIBlockKind.ForwardReferences); + GenerateForwardRefs(); + PopBlock(NewLineKind.BeforeNextBlock); + GenerateNamespace(TranslationUnit); PushBlock(BlockKind.Footer); @@ -72,27 +77,61 @@ namespace CppSharp.Generators.CLI WriteLine(include); } - public void GenerateForwardRefs(Namespace @namespace) + private Namespace FindCreateNamespace(Namespace @namespace, Declaration decl) { - var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); - typeReferenceCollector.Process(@namespace, filterNamespaces: true); + if (decl.Namespace is TranslationUnit) + return @namespace; - // Use a set to remove duplicate entries. - var forwardRefs = new SortedSet(StringComparer.InvariantCulture); + var childNamespaces = decl.Namespace.GatherParentNamespaces(); + var currentNamespace = @namespace; - foreach (var typeRef in typeReferenceCollector.TypeReferences) + foreach (var child in childNamespaces) + currentNamespace = currentNamespace.FindCreateNamespace(child.Name); + + return currentNamespace; + } + + public Namespace ConvertForwardReferencesToNamespaces( + IEnumerable typeReferences) + { + // Create a new tree of namespaces out of the type references found. + var rootNamespace = new Namespace(); + + foreach (var typeRef in typeReferences) { - var @ref = typeRef.FowardReference; - if(!string.IsNullOrEmpty(@ref) && !typeRef.Include.InHeader) - forwardRefs.Add(@ref); + if (string.IsNullOrWhiteSpace(typeRef.FowardReference)) + continue; + + var declaration = typeRef.Declaration; + if (!(declaration.Namespace is Namespace)) + continue; + + var @namespace = FindCreateNamespace(rootNamespace, declaration); + @namespace.TypeReferences.Add(typeRef); } - foreach (var forwardRef in forwardRefs) - WriteLine(forwardRef); + return rootNamespace; + } + + public void GenerateForwardRefs() + { + var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); + typeReferenceCollector.Process(TranslationUnit); + + var typeReferences = typeReferenceCollector.TypeReferences; + var @namespace = ConvertForwardReferencesToNamespaces(typeReferences); + + GenerateDeclContext(@namespace); } public void GenerateDeclContext(DeclarationContext decl) { + // Generate all the type references for the module. + foreach (var typeRef in decl.TypeReferences) + { + WriteLine(typeRef.FowardReference); + } + // Generate all the enum declarations for the module. foreach (var @enum in decl.Enums) { @@ -142,11 +181,6 @@ namespace CppSharp.Generators.CLI WriteStartBraceIndent(); } - // Generate the forward references. - PushBlock(CLIBlockKind.ForwardReferences); - GenerateForwardRefs(@namespace); - PopBlock(NewLineKind.BeforeNextBlock); - GenerateDeclContext(@namespace); if (generateNamespace) diff --git a/src/Generator/Generators/CLI/CLITypeReferences.cs b/src/Generator/Generators/CLI/CLITypeReferences.cs index fdc4c6fd..1290b0b6 100644 --- a/src/Generator/Generators/CLI/CLITypeReferences.cs +++ b/src/Generator/Generators/CLI/CLITypeReferences.cs @@ -5,23 +5,25 @@ using CppSharp.Types; namespace CppSharp.Generators.CLI { - public class CLITypeReference + public class CLITypeReference : TypeReference { public Include Include; - public string FowardReference; public override string ToString() { - return FowardReference; + if (!string.IsNullOrWhiteSpace(FowardReference)) + return FowardReference; + + return Include.ToString(); } } public class CLITypeReferenceCollector : AstVisitor { - private Dictionary typeReferences; private readonly ITypeMapDatabase TypeMapDatabase; private TranslationUnit TranslationUnit; + private Dictionary typeReferences; public IEnumerable TypeReferences { get { return typeReferences.Values; } @@ -38,8 +40,9 @@ namespace CppSharp.Generators.CLI if(typeReferences.ContainsKey(decl)) return typeReferences[decl]; - var @ref = new CLITypeReference(); + var @ref = new CLITypeReference { Declaration = decl }; typeReferences.Add(decl, @ref); + return @ref; } @@ -55,13 +58,13 @@ namespace CppSharp.Generators.CLI return GetEffectiveNamespace(@namespace); } - public void Process(Namespace @namespace, bool filterNamespaces) + public void Process(Namespace @namespace, bool filterNamespaces = false) { - var collector = new RecordCollector(@namespace.TranslationUnit); - @namespace.Visit(collector); - TranslationUnit = @namespace.TranslationUnit; + var collector = new RecordCollector(TranslationUnit); + @namespace.Visit(collector); + foreach (var record in collector.Declarations) { if (record.Value is Namespace) @@ -69,7 +72,7 @@ namespace CppSharp.Generators.CLI if (filterNamespaces) { - var declNamespace = GetEffectiveNamespace(record.Value.Namespace); + var declNamespace = GetEffectiveNamespace(record.Value); var isSameNamespace = declNamespace == @namespace; if (declNamespace != null) @@ -88,10 +91,9 @@ namespace CppSharp.Generators.CLI private void ProcessTypeMap(ASTRecord record) { TypeMap typeMap; - if (!TypeMapDatabase.FindTypeMap(record.Value, out typeMap)) return; + if (!TypeMapDatabase.FindTypeMap(record.Value, out typeMap)) + return; - // Typemap must explicitly set the include file when one is required. - GetTypeReference(record.Value).Include.File = ""; typeMap.Declaration = record.Value; typeMap.CLITypeReference(this, record); @@ -114,9 +116,6 @@ namespace CppSharp.Generators.CLI if(IsBuiltinTypedef(decl)) return; - if (declFile.Contains("String")) - return; - var typeRef = GetTypeReference(decl); typeRef.Include = new Include() {