diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index f794b39e..c715d347 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -44,7 +44,7 @@ namespace CppSharp.AST private string name; // Name of the declaration. - public string Name + public virtual string Name { get { return name; } set @@ -67,7 +67,7 @@ namespace CppSharp.AST } // Name of the declaration. - public string OriginalName; + public virtual string OriginalName { get; set;} public string QualifiedOriginalName { diff --git a/src/AST/Template.cs b/src/AST/Template.cs index dbce1df7..637400a0 100644 --- a/src/AST/Template.cs +++ b/src/AST/Template.cs @@ -41,6 +41,40 @@ namespace CppSharp.AST { return visitor.VisitClassTemplateDecl(this); } + + public override string Name + { + get + { + if(TemplatedDecl != null) + return TemplatedClass.Name; + return base.Name; + } + set + { + if(TemplatedDecl != null) + TemplatedClass.Name = value; + else + base.Name = value; + } + } + + public override string OriginalName + { + get + { + if(TemplatedDecl != null) + return TemplatedClass.OriginalName; + return base.OriginalName; + } + set + { + if(TemplatedDecl != null) + TemplatedClass.OriginalName = value; + else + base.OriginalName = value; + } + } } public class ClassTemplateSpecialization : Class diff --git a/src/Generator/AST/ASTRecord.cs b/src/Generator/AST/ASTRecord.cs new file mode 100644 index 00000000..68155ea9 --- /dev/null +++ b/src/Generator/AST/ASTRecord.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using CppSharp.AST; +using Type = CppSharp.AST.Type; + +namespace CppSharp.Generators.AST +{ + public class ASTRecord + { + public ASTRecord Parent; + public object Object; + + public bool GetParent(out T @out) + { + @out = default(T); + + if (Parent == null) + return false; + + var v = Parent.Object; + if (!(v is T)) + return false; + + @out = (T) v; + return true; + } + + // Pushes ancestors into the stack until it is found one of type T. + public bool GetAncestors(ref Stack ancestors) + { + ancestors.Push(this); + + T value; + if (GetParent(out value)) + { + ancestors.Push(value); + return true; + } + + return Parent != null + && Parent.GetAncestors(ref ancestors); + } + } + + public class ASTRecord : ASTRecord + { + public T Value + { + get { return (T) Object; } + } + } + + public class ASTRecordStack + { + private readonly Stack recordStack; + + public ASTRecordStack() + { + recordStack = new Stack(); + } + + public ASTRecord Push(T value) + { + ASTRecord parent = null; + + if (recordStack.Count > 0) + parent = recordStack.Peek(); + + var record = new ASTRecord() + { + Parent = parent, + Object = value + }; + recordStack.Push(record); + return record; + } + + public void Pop() + { + recordStack.Pop(); + } + } + + static class ASTRecordExtensions + { + public static bool IsBaseClass(this ASTRecord record) + { + Class decl; + return record.GetParent(out decl) && decl.BaseClass == record.Object; + } + + public static bool IsFieldValueType(this ASTRecord record) + { + var ancestors = new Stack(); + if(!record.GetAncestors(ref ancestors)) + return false; + + var field = (Field)ancestors.Pop(); + + Class decl; + if (!field.Type.Desugar().IsTagDecl(out decl)) + return false; + + return decl.IsValueType; + } + } + + public class RecordCollector : AstVisitor + { + public readonly ISet> Declarations; + private readonly ASTRecordStack recordStack; + + public TranslationUnit translationUnit; + + public ISet Visited2 { get; private set; } + public bool AlreadyVisited2(object o) + { + return !Visited2.Add(o); + } + + public RecordCollector(TranslationUnit translationUnit) + { + this.translationUnit = translationUnit; + Declarations = new HashSet>(); + recordStack = new ASTRecordStack(); + Visited2 = new HashSet(); + } + + public override bool VisitDeclaration(Declaration decl) + { + if(translationUnit.FileName.Contains("Font")) + Console.Write(""); + + if (decl.IsIncomplete && decl.CompleteDeclaration != null) + decl = decl.CompleteDeclaration; + + if(AlreadyVisited2(decl)) + return ShouldVisitChilds(decl); + Visited.Remove(decl); // So Class can be revisited + + Declarations.Add(recordStack.Push(decl)); + decl.Visit(this); + recordStack.Pop(); + + return false; + } + + public override bool VisitType(Type type, TypeQualifiers quals) + { + type = type.Desugar(); + + if(AlreadyVisited2(type)) + return true; + + recordStack.Push(type); + type.Visit(this); + recordStack.Pop(); + + return false; + } + + public bool ShouldVisitChilds(Declaration decl) + { + if(decl == translationUnit) + return true; + + if (decl is TranslationUnit) + return false; + + if (decl.Namespace == null) + return true; + + // No need to continue visiting after a declaration of + // another translation unit is encountered. + return decl.Namespace.TranslationUnit == translationUnit; + } + } +} diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 13baae63..c0cf56b3 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -131,7 +131,6 @@ namespace CppSharp { Passes.CleanInvalidDeclNames(); Passes.CheckIgnoredDecls(); - Passes.CheckTypeReferences(); Passes.CheckFlagEnums(); Passes.CheckAmbiguousOverloads(); Generator.SetupPasses(Passes); diff --git a/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs b/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs deleted file mode 100644 index 5b767234..00000000 --- a/src/Generator/Generators/CLI/CLIForwardReferencePrinter.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using CppSharp.AST; - -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; - private TypeReference currentTypeReference; - - public CLIForwardReferencePrinter(TypeRefsVisitor typeRefs) - { - Includes = new List(); - Refs = new List(); - TypeRefs = typeRefs; - } - - 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) - { - throw new NotImplementedException(); - } - - 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 02faded7..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); - 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); - 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/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index ca98abdd..83f5ecba 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using CppSharp.AST; using CppSharp.Types; +using Type = CppSharp.AST.Type; namespace CppSharp.Generators.CLI { @@ -340,7 +341,7 @@ namespace CppSharp.Generators.CLI throw new NotImplementedException(); } - public string ToString(AST.Type type) + public string ToString(Type type) { return type.Visit(this); } 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/Generators/CSharp/CSharpGenerator.cs b/src/Generator/Generators/CSharp/CSharpGenerator.cs index 2e429eee..30d75eea 100644 --- a/src/Generator/Generators/CSharp/CSharpGenerator.cs +++ b/src/Generator/Generators/CSharp/CSharpGenerator.cs @@ -13,7 +13,7 @@ namespace CppSharp.Generators.CSharp public CSharpGenerator(Driver driver) : base(driver) { typePrinter = new CSharpTypePrinter(driver.TypeDatabase, driver.Library); - AST.Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type; + CppSharp.AST.Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type; } public override List