Browse Source

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.
pull/86/head
triton 12 years ago
parent
commit
b91ac99576
  1. 19
      src/AST/Namespace.cs
  2. 3
      src/AST/TranslationUnit.cs
  3. 68
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  4. 31
      src/Generator/Generators/CLI/CLITypeReferences.cs

19
src/AST/Namespace.cs

@ -19,6 +19,7 @@ namespace CppSharp.AST
public List<TypedefDecl> Typedefs; public List<TypedefDecl> Typedefs;
public List<Variable> Variables; public List<Variable> Variables;
public List<Event> Events; public List<Event> Events;
public List<TypeReference> TypeReferences;
// Used to keep track of anonymous declarations. // Used to keep track of anonymous declarations.
public Dictionary<ulong, Declaration> Anonymous; public Dictionary<ulong, Declaration> Anonymous;
@ -44,9 +45,27 @@ namespace CppSharp.AST
Typedefs = new List<TypedefDecl>(); Typedefs = new List<TypedefDecl>();
Variables = new List<Variable>(); Variables = new List<Variable>();
Events = new List<Event>(); Events = new List<Event>();
TypeReferences = new List<TypeReference>();
Anonymous = new Dictionary<ulong, Declaration>(); Anonymous = new Dictionary<ulong, Declaration>();
} }
public IEnumerable<DeclarationContext> GatherParentNamespaces()
{
var children = new List<DeclarationContext>();
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) public Declaration FindAnonymous(ulong key)
{ {
return Anonymous.ContainsKey(key) ? Anonymous[key] : null; return Anonymous.ContainsKey(key) ? Anonymous[key] : null;

3
src/AST/TranslationUnit.cs

@ -57,8 +57,5 @@ namespace CppSharp.AST
/// Contains the include path. /// Contains the include path.
public string IncludePath; public string IncludePath;
/// Type references object.
public object TypeReferences;
} }
} }

68
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -30,13 +30,18 @@ namespace CppSharp.Generators.CLI
if (Options.OutputInteropIncludes) if (Options.OutputInteropIncludes)
WriteLine("#include \"CppSharp.h\""); WriteLine("#include \"CppSharp.h\"");
// Generate #include forward references.
PushBlock(CLIBlockKind.IncludesForwardReferences); PushBlock(CLIBlockKind.IncludesForwardReferences);
WriteLine("#include <{0}>", TranslationUnit.IncludePath); WriteLine("#include <{0}>", TranslationUnit.IncludePath);
GenerateIncludeForwardRefs(); GenerateIncludeForwardRefs();
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
PopBlock(NewLineKind.Always); PopBlock(NewLineKind.Always);
// Generate namespace for forward references.
PushBlock(CLIBlockKind.ForwardReferences);
GenerateForwardRefs();
PopBlock(NewLineKind.BeforeNextBlock);
GenerateNamespace(TranslationUnit); GenerateNamespace(TranslationUnit);
PushBlock(BlockKind.Footer); PushBlock(BlockKind.Footer);
@ -72,27 +77,61 @@ namespace CppSharp.Generators.CLI
WriteLine(include); WriteLine(include);
} }
public void GenerateForwardRefs(Namespace @namespace) private Namespace FindCreateNamespace(Namespace @namespace, Declaration decl)
{ {
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); if (decl.Namespace is TranslationUnit)
typeReferenceCollector.Process(@namespace, filterNamespaces: true); return @namespace;
// Use a set to remove duplicate entries. var childNamespaces = decl.Namespace.GatherParentNamespaces();
var forwardRefs = new SortedSet<string>(StringComparer.InvariantCulture); 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<CLITypeReference> 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.IsNullOrWhiteSpace(typeRef.FowardReference))
if(!string.IsNullOrEmpty(@ref) && !typeRef.Include.InHeader) continue;
forwardRefs.Add(@ref);
var declaration = typeRef.Declaration;
if (!(declaration.Namespace is Namespace))
continue;
var @namespace = FindCreateNamespace(rootNamespace, declaration);
@namespace.TypeReferences.Add(typeRef);
} }
foreach (var forwardRef in forwardRefs) return rootNamespace;
WriteLine(forwardRef); }
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) 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. // Generate all the enum declarations for the module.
foreach (var @enum in decl.Enums) foreach (var @enum in decl.Enums)
{ {
@ -142,11 +181,6 @@ namespace CppSharp.Generators.CLI
WriteStartBraceIndent(); WriteStartBraceIndent();
} }
// Generate the forward references.
PushBlock(CLIBlockKind.ForwardReferences);
GenerateForwardRefs(@namespace);
PopBlock(NewLineKind.BeforeNextBlock);
GenerateDeclContext(@namespace); GenerateDeclContext(@namespace);
if (generateNamespace) if (generateNamespace)

31
src/Generator/Generators/CLI/CLITypeReferences.cs

@ -5,23 +5,25 @@ using CppSharp.Types;
namespace CppSharp.Generators.CLI namespace CppSharp.Generators.CLI
{ {
public class CLITypeReference public class CLITypeReference : TypeReference
{ {
public Include Include; public Include Include;
public string FowardReference;
public override string ToString() public override string ToString()
{ {
return FowardReference; if (!string.IsNullOrWhiteSpace(FowardReference))
return FowardReference;
return Include.ToString();
} }
} }
public class CLITypeReferenceCollector : AstVisitor public class CLITypeReferenceCollector : AstVisitor
{ {
private Dictionary<Declaration, CLITypeReference> typeReferences;
private readonly ITypeMapDatabase TypeMapDatabase; private readonly ITypeMapDatabase TypeMapDatabase;
private TranslationUnit TranslationUnit; private TranslationUnit TranslationUnit;
private Dictionary<Declaration, CLITypeReference> typeReferences;
public IEnumerable<CLITypeReference> TypeReferences public IEnumerable<CLITypeReference> TypeReferences
{ {
get { return typeReferences.Values; } get { return typeReferences.Values; }
@ -38,8 +40,9 @@ namespace CppSharp.Generators.CLI
if(typeReferences.ContainsKey(decl)) if(typeReferences.ContainsKey(decl))
return typeReferences[decl]; return typeReferences[decl];
var @ref = new CLITypeReference(); var @ref = new CLITypeReference { Declaration = decl };
typeReferences.Add(decl, @ref); typeReferences.Add(decl, @ref);
return @ref; return @ref;
} }
@ -55,13 +58,13 @@ namespace CppSharp.Generators.CLI
return GetEffectiveNamespace(@namespace); 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; TranslationUnit = @namespace.TranslationUnit;
var collector = new RecordCollector(TranslationUnit);
@namespace.Visit(collector);
foreach (var record in collector.Declarations) foreach (var record in collector.Declarations)
{ {
if (record.Value is Namespace) if (record.Value is Namespace)
@ -69,7 +72,7 @@ namespace CppSharp.Generators.CLI
if (filterNamespaces) if (filterNamespaces)
{ {
var declNamespace = GetEffectiveNamespace(record.Value.Namespace); var declNamespace = GetEffectiveNamespace(record.Value);
var isSameNamespace = declNamespace == @namespace; var isSameNamespace = declNamespace == @namespace;
if (declNamespace != null) if (declNamespace != null)
@ -88,10 +91,9 @@ namespace CppSharp.Generators.CLI
private void ProcessTypeMap(ASTRecord<Declaration> record) private void ProcessTypeMap(ASTRecord<Declaration> record)
{ {
TypeMap typeMap; 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.Declaration = record.Value;
typeMap.CLITypeReference(this, record); typeMap.CLITypeReference(this, record);
@ -114,9 +116,6 @@ namespace CppSharp.Generators.CLI
if(IsBuiltinTypedef(decl)) if(IsBuiltinTypedef(decl))
return; return;
if (declFile.Contains("String"))
return;
var typeRef = GetTypeReference(decl); var typeRef = GetTypeReference(decl);
typeRef.Include = new Include() typeRef.Include = new Include()
{ {

Loading…
Cancel
Save