diff --git a/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs b/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs deleted file mode 100644 index 61fd5123..00000000 --- a/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs +++ /dev/null @@ -1,235 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using CppSharp.AST; -using CppSharp.Types; - -namespace CppSharp.Generators.CLI -{ - public struct CLIForwardReference - { - public Declaration Declaration; - public Namespace Namespace; - public string Text; - } - - public class CLIForwardReferencePrinter : IDeclVisitor - { - public readonly IList Includes; - public readonly IList Refs; - private readonly TypeRefsVisitor TypeRefs; - public TypeReference CurrentTypeReference; - private readonly ITypeMapDatabase TypeMapDatabase; - - public CLIForwardReferencePrinter(TypeRefsVisitor typeRefs, ITypeMapDatabase typeMapDatabase) - { - Includes = new List(); - Refs = new List(); - TypeRefs = typeRefs; - TypeMapDatabase = typeMapDatabase; - } - - public void Process() - { - foreach (var typeRef in TypeRefs.References) - { - CurrentTypeReference = typeRef; - typeRef.Declaration.Visit(this); - } - - foreach (var baseClass in TypeRefs.Bases) - VisitBaseClass(baseClass); - } - - public void VisitBaseClass(Class @class) - { - if (@class.IsIncomplete) - @class = @class.CompleteDeclaration as Class; - - if (@class == null) - return; - - Includes.Add(GetHeaderFromDecl(@class)); - } - - public bool VisitDeclaration(Declaration decl) - { - throw new NotImplementedException(); - } - - public bool VisitClassDecl(Class @class) - { - var completeDecl = @class.CompleteDeclaration as Class; - if (@class.IsIncomplete && completeDecl != null) - return VisitClassDecl(completeDecl); - - if (@class.IsValueType) - { - Refs.Add(new CLIForwardReference() - { - Declaration = @class, - Namespace = CurrentTypeReference.Namespace, - Text = string.Format("value struct {0};", @class.Name) - }); - - return true; - } - - Refs.Add(new CLIForwardReference() - { - Declaration = @class, - Namespace = CurrentTypeReference.Namespace, - Text = string.Format("ref class {0};", @class.Name) - }); - - return true; - } - - public bool VisitFieldDecl(Field field) - { - Class @class; - if (field.Type.IsTagDecl(out @class)) - { - if (@class.IsValueType) - Includes.Add(GetHeaderFromDecl(@class)); - else - VisitClassDecl(@class); - - return true; - } - - Enumeration @enum; - if (field.Type.IsTagDecl(out @enum)) - return VisitEnumDecl(@enum); - - Includes.Add(GetHeaderFromDecl(field)); - return true; - } - - public bool VisitFunctionDecl(Function function) - { - throw new NotImplementedException(); - } - - public bool VisitMethodDecl(Method method) - { - throw new NotImplementedException(); - } - - public bool VisitParameterDecl(Parameter parameter) - { - throw new NotImplementedException(); - } - - public string GetHeaderFromDecl(Declaration decl) - { - var @namespace = decl.Namespace; - var unit = @namespace.TranslationUnit; - - if (unit.Ignore) - return string.Empty; - - if (unit.IsSystemHeader) - return string.Empty; - - return Path.GetFileNameWithoutExtension(unit.FileName); - } - - public bool VisitTypedefDecl(TypedefDecl typedef) - { - FunctionType function; - if (typedef.Type.IsPointerTo(out function)) - { - Includes.Add(GetHeaderFromDecl(typedef)); - return true; - } - - throw new NotImplementedException(); - } - - public bool VisitEnumDecl(Enumeration @enum) - { - Includes.Add(GetHeaderFromDecl(@enum)); - - if (@enum.Type.IsPrimitiveType(PrimitiveType.Int32)) - { - Refs.Add(new CLIForwardReference() - { - Declaration = @enum, - Namespace = CurrentTypeReference.Namespace, - Text = string.Format("enum struct {0};", @enum.Name) - }); - - return true; - } - - Refs.Add(new CLIForwardReference() - { - Declaration = @enum, - Namespace = CurrentTypeReference.Namespace, - Text = string.Format("enum struct {0} : {1};", @enum.Name, @enum.Type) - }); - return true; - } - - public bool VisitVariableDecl(Variable variable) - { - throw new NotImplementedException(); - } - - public bool VisitClassTemplateDecl(ClassTemplate template) - { - var decl = template.TemplatedDecl; - - TypeMap typeMap = null; - if (TypeMapDatabase.FindTypeMap(decl, out typeMap)) - { - typeMap.Declaration = decl; - typeMap.CLIForwardReference(this); - return true; - } - - if(decl.Ignore) - return true; - - Includes.Add(GetHeaderFromDecl(template)); - - var @params = string.Empty; - for(var i = 0; i < template.Parameters.Count; i++) - @params = string.Format("{0}{1}typename {2}", @params, (i>0)? ", " : "", template.Parameters[i].Name); - - Refs.Add(new CLIForwardReference() - { - Declaration = template, - Namespace = CurrentTypeReference.Namespace, - Text = string.Format("generic<{0}> ref class {1};", @params, template.TemplatedClass.QualifiedName) - }); - return true; - } - - public bool VisitFunctionTemplateDecl(FunctionTemplate template) - { - throw new NotImplementedException(); - } - - public bool VisitMacroDefinition(MacroDefinition macro) - { - throw new NotImplementedException(); - } - - public bool VisitNamespace(Namespace @namespace) - { - throw new NotImplementedException(); - } - - public bool VisitEvent(Event @event) - { - throw new NotImplementedException(); - } - - public bool VisitProperty(Property property) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 4ea8e214..6edc0f41 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -46,47 +46,38 @@ namespace CppSharp.Generators.CLI public void GenerateIncludeForwardRefs() { - var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; - - var forwardRefsPrinter = new CLIForwardReferencePrinter(typeRefs, Driver.TypeDatabase); - forwardRefsPrinter.Process(); + var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); + typeReferenceCollector.Process(TranslationUnit); var includes = new SortedSet(StringComparer.InvariantCulture); - foreach (var include in forwardRefsPrinter.Includes) - { - if (string.IsNullOrWhiteSpace(include)) - continue; - - if (include == Path.GetFileNameWithoutExtension(TranslationUnit.FileName)) + foreach (var typeRef in typeReferenceCollector.TypeReferences) + { + if (typeRef.Include.File == TranslationUnit.FileName) continue; - includes.Add(string.Format("#include \"{0}.h\"", include)); + var include = typeRef.Include; + if(!string.IsNullOrEmpty(include.File) && include.InHeader) + includes.Add(include.ToString()); } - foreach (var include in Includes) - includes.Add(include.ToString()); - foreach (var include in includes) WriteLine(include); } public void GenerateForwardRefs(Namespace @namespace) { - var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; - - var forwardRefsPrinter = new CLIForwardReferencePrinter(typeRefs, Driver.TypeDatabase); - forwardRefsPrinter.Process(); + var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); + typeReferenceCollector.Process(@namespace); // Use a set to remove duplicate entries. var forwardRefs = new SortedSet(StringComparer.InvariantCulture); - foreach (var forwardRef in forwardRefsPrinter.Refs) + foreach (var typeRef in typeReferenceCollector.TypeReferences) { - if (forwardRef.Namespace != @namespace) - continue; - - forwardRefs.Add(forwardRef.Text); + var @ref = typeRef.FowardReference; + if(!string.IsNullOrEmpty(@ref) && !typeRef.Include.InHeader) + forwardRefs.Add(@ref); } foreach (var forwardRef in forwardRefs) @@ -259,8 +250,8 @@ namespace CppSharp.Generators.CLI PushIndent(); WriteLine("property System::IntPtr Instance"); WriteStartBraceIndent(); - WriteLine("virtual System::IntPtr get();"); - WriteLine("virtual void set(System::IntPtr instance);"); + WriteLine("virtual System::IntPtr get() override;"); + WriteLine("virtual void set(System::IntPtr instance) override;"); WriteCloseBraceIndent(); NewLine(); diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 2d74ad4f..944c03a6 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -52,38 +52,22 @@ namespace CppSharp.Generators.CLI public void GenerateForwardReferenceHeaders() { PushBlock(CLIBlockKind.IncludesForwardReferences); - var includes = new SortedSet(StringComparer.InvariantCulture); - - var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; - - // Generate the forward references. - foreach (var forwardRef in typeRefs.References) - { - var decl = forwardRef.Declaration; - - if (decl.IsIncomplete && decl.CompleteDeclaration != null) - decl = decl.CompleteDeclaration; - var @namespace = decl.Namespace; - var translationUnit = @namespace.TranslationUnit; + var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase); + typeReferenceCollector.Process(TranslationUnit); - if (translationUnit.Ignore) - continue; - - if (translationUnit.IsSystemHeader) - continue; - - var includeName = Path.GetFileNameWithoutExtension(translationUnit.FileName); + var includes = new SortedSet(StringComparer.InvariantCulture); - if (includeName == Path.GetFileNameWithoutExtension(TranslationUnit.FileName)) + foreach (var typeRef in typeReferenceCollector.TypeReferences) + { + if (typeRef.Include.File == TranslationUnit.FileName) continue; - includes.Add(string.Format("#include \"{0}.h\"", includeName.Replace('\\', '/'))); + var include = typeRef.Include; + if(!string.IsNullOrEmpty(include.File) && !include.InHeader) + includes.Add(include.ToString()); } - foreach (var include in Includes) - includes.Add(include.ToString()); - foreach (var include in includes) WriteLine(include); @@ -726,8 +710,7 @@ namespace CppSharp.Generators.CLI if (IsNativeFunctionOrStaticMethod(function)) { - Write("::"); - Write("{0}(", function.QualifiedOriginalName); + Write("::{0}(", function.QualifiedOriginalName); } else { diff --git a/src/Generator/Generators/CLI/CLITextTemplate.cs b/src/Generator/Generators/CLI/CLITextTemplate.cs index e4f497f3..591aa598 100644 --- a/src/Generator/Generators/CLI/CLITextTemplate.cs +++ b/src/Generator/Generators/CLI/CLITextTemplate.cs @@ -15,6 +15,7 @@ namespace CppSharp.Generators.CLI public string File; public IncludeKind Kind; + public bool InHeader; public override string ToString() { diff --git a/src/Generator/Generators/CLI/CLITypeReferences.cs b/src/Generator/Generators/CLI/CLITypeReferences.cs new file mode 100644 index 00000000..7ad47d32 --- /dev/null +++ b/src/Generator/Generators/CLI/CLITypeReferences.cs @@ -0,0 +1,162 @@ +using System.Collections.Generic; +using CppSharp.AST; +using CppSharp.Generators.AST; +using CppSharp.Types; + +namespace CppSharp.Generators.CLI +{ + public class CLITypeReference + { + public Include Include; + public string FowardReference; + } + + public class CLITypeReferenceCollector : AstVisitor + { + private Dictionary typeReferences; + private readonly ITypeMapDatabase TypeMapDatabase; + private TranslationUnit TranslationUnit; + + public IEnumerable TypeReferences + { + get { return typeReferences.Values; } + } + + public CLITypeReferenceCollector(ITypeMapDatabase typeMapDatabase) + { + TypeMapDatabase = typeMapDatabase; + typeReferences = new Dictionary(); + } + + public CLITypeReference GetTypeReference(Declaration decl) + { + if(typeReferences.ContainsKey(decl)) + return typeReferences[decl]; + + var @ref = new CLITypeReference(); + typeReferences.Add(decl, @ref); + return @ref; + } + + public void Process(Namespace @namespace) + { + var collector = new RecordCollector(@namespace.TranslationUnit); + @namespace.Visit(collector); + + TranslationUnit = @namespace.TranslationUnit; + + foreach (var record in collector.Declarations) + { + record.Value.Visit(this); + GenerateInclude(record); + ProcessTypeMap(record); + } + } + + private void ProcessTypeMap(ASTRecord record) + { + TypeMap typeMap; + 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); + } + + private void GenerateInclude(ASTRecord record) + { + var decl = record.Value; + if(decl.Namespace == null) + return; + + var declFile = decl.Namespace.TranslationUnit.FileName; + + if(decl.Namespace.TranslationUnit.IsSystemHeader) + return; + + if(decl.Ignore) + return; + + if(IsBuiltinTypedef(decl)) + return; + + if (declFile.Contains("String")) + return; + + GetTypeReference(decl).Include = new Include() + { + File = declFile, + Kind = Include.IncludeKind.Quoted, + InHeader = IsIncludeInHeader(record) + }; + } + + private bool IsBuiltinTypedef(Declaration decl) + { + var typedefDecl = decl as TypedefDecl; + if(typedefDecl == null) return false; + if(typedefDecl.Type is BuiltinType) return true; + + var typedefType = typedefDecl.Type as TypedefType; + if(typedefType == null) return false; + if(typedefType.Declaration == null) return false; + + return typedefType.Declaration.Type is BuiltinType; + } + + private bool IsIncludeInHeader(ASTRecord record) + { + return record.IsBaseClass() || record.IsFieldValueType(); + } + + public override bool VisitDeclaration(Declaration decl) + { + return ShouldVisitDecl(decl); + } + + public override bool VisitClassDecl(Class @class) + { + if(!ShouldVisitDecl(@class)) + return false; + + if (@class.IsIncomplete && @class.CompleteDeclaration != null) + @class = (Class) @class.CompleteDeclaration; + + var keywords = @class.IsValueType? "value struct" : "ref class"; + var @ref = string.Format("{0} {1};", keywords, @class.Name); + + GetTypeReference(@class).FowardReference = @ref; + + return false; + } + + public override bool VisitEnumDecl(Enumeration @enum) + { + if(!ShouldVisitDecl(@enum)) + return false; + + var @base = ""; + if(!@enum.Type.IsPrimitiveType(PrimitiveType.Int32)) + @base = string.Format(" : {0}", @enum.Type); + + var @ref = string.Format("enum struct {0}{1};", @enum.Name, @base); + + GetTypeReference(@enum).FowardReference = @ref; + + return false; + } + + private bool ShouldVisitDecl(Declaration decl) + { + if(decl.Namespace != null && decl.Namespace.TranslationUnit.IsSystemHeader) + return false; + + if (decl.Ignore) + return false; + + return true; + } + } +} \ No newline at end of file diff --git a/src/Generator/Types/TypeMap.cs b/src/Generator/Types/TypeMap.cs index 512bedca..ad4b7eff 100644 --- a/src/Generator/Types/TypeMap.cs +++ b/src/Generator/Types/TypeMap.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using CppSharp.AST; using CppSharp.Generators; +using CppSharp.Generators.AST; using CppSharp.Generators.CLI; using CppSharp.Generators.CSharp; using Type = CppSharp.AST.Type; @@ -65,7 +66,7 @@ namespace CppSharp.Types throw new NotImplementedException(); } - public virtual void CLIForwardReference(CLIForwardReferencePrinter ctx) + public virtual void CLITypeReference(CLITypeReferenceCollector collector, ASTRecord loc) { }