From b91ac99576d1e1b3fd7366afb6d39c7ca88fae94 Mon Sep 17 00:00:00 2001 From: triton Date: Sat, 12 Oct 2013 03:10:54 +0100 Subject: [PATCH] Reworked the CLI type references collector and generation code. We now properly handle type references to namespaces that do not exist in the referencing translation unit. We do this by collecting all the references for all namespaces in the translation unit and generate a block with all the forward references. --- src/AST/Namespace.cs | 19 ++++++ src/AST/TranslationUnit.cs | 3 - .../Generators/CLI/CLIHeadersTemplate.cs | 68 ++++++++++++++----- .../Generators/CLI/CLITypeReferences.cs | 31 ++++----- 4 files changed, 85 insertions(+), 36 deletions(-) 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() {