From 344656c7879a41a12921e428bdfe87b4897dd7f0 Mon Sep 17 00:00:00 2001 From: Ali Alamiri Date: Fri, 3 Apr 2020 13:37:14 +0100 Subject: [PATCH] Move the GenerateInclude logic to GetTypeReference (#1319) Improve generation of forward references and includes in C++/CLI. Move the GenerateInclude logic to GetTypeReference so that an include is also generated for visited types of an ASTRecord that are forward declared, and come from typedef of ignored class template. Co-authored-by: Build Agent --- build/Tests.lua | 4 +- .../Generators/CLI/CLITypeReferences.cs | 69 +++++++++++-------- src/Generator/Types/Std/Stdlib.cs | 13 ++-- tests/CLI/CLI.Tests.cs | 9 +++ tests/CLI/CLI.cs | 54 +++++++++++++++ tests/CLI/CLI.h | 3 + .../Employee.cpp | 6 ++ .../Employee.h | 10 +++ .../EmployeeForwardDecl.h | 4 ++ .../EmployeeOrg.cpp | 13 ++++ .../EmployeeOrg.h | 13 ++++ .../IgnoredClassTemplateForEmployee.h | 13 ++++ tests/CLI/premake4.lua | 2 +- 13 files changed, 177 insertions(+), 36 deletions(-) create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h create mode 100644 tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h diff --git a/build/Tests.lua b/build/Tests.lua index 4e25dd44..6aa31a9a 100644 --- a/build/Tests.lua +++ b/build/Tests.lua @@ -31,10 +31,10 @@ function SetupTestCSharp(name) SetupTestProjectsCSharp(name) end -function SetupTestCLI(name) +function SetupTestCLI(name, extraFiles, suffix) SetupTestGeneratorProject(name) SetupTestNativeProject(name) - SetupTestProjectsCLI(name) + SetupTestProjectsCLI(name, extraFiles, suffix) end function SetupManagedTestProject() diff --git a/src/Generator/Generators/CLI/CLITypeReferences.cs b/src/Generator/Generators/CLI/CLITypeReferences.cs index a173edac..8a1c795f 100644 --- a/src/Generator/Generators/CLI/CLITypeReferences.cs +++ b/src/Generator/Generators/CLI/CLITypeReferences.cs @@ -48,10 +48,25 @@ namespace CppSharp.Generators.CLI if (typeReferences.ContainsKey(decl)) return typeReferences[decl]; - var @ref = new CLITypeReference { Declaration = decl }; - typeReferences.Add(decl, @ref); + var translationUnit = decl.Namespace.TranslationUnit; + + if (ShouldIncludeTranslationUnit(translationUnit) && decl.IsGenerated && !IsBuiltinTypedef(decl)) + { + var @ref = new CLITypeReference { Declaration = decl }; + + @ref.Include = new CInclude + { + File = GetIncludePath(translationUnit), + TranslationUnit = translationUnit, + Kind = translationUnit.IsGenerated ? CInclude.IncludeKind.Quoted : CInclude.IncludeKind.Angled + }; - return @ref; + typeReferences.Add(decl, @ref); + + return @ref; + } + + return null; } static Namespace GetEffectiveNamespace(Declaration decl) @@ -104,39 +119,27 @@ namespace CppSharp.Generators.CLI if (decl.Namespace == null) return; + var typedefType = record.Value as TypedefNameDecl; + // Find a type map for the declaration and use it if it exists. TypeMap typeMap; - if (TypeMapDatabase.FindTypeMap(record.Value, out typeMap)) + if (TypeMapDatabase.FindTypeMap(record.Value, out typeMap) + || (typedefType != null && TypeMapDatabase.FindTypeMap(typedefType.Type.Desugar(), out typeMap))) { typeMap.CLITypeReference(this, record); return; } - var translationUnit = decl.Namespace.TranslationUnit; - - if (translationUnit.IsSystemHeader || !translationUnit.IsValid) - return; - - if (!decl.IsGenerated) - return; - - if (IsBuiltinTypedef(decl)) - return; - var typeRef = GetTypeReference(decl); - if (typeRef.Include.TranslationUnit == null) + if(typeRef != null) { - typeRef.Include = new CInclude - { - File = GetIncludePath(translationUnit), - TranslationUnit = translationUnit, - Kind = translationUnit.IsGenerated - ? CInclude.IncludeKind.Quoted - : CInclude.IncludeKind.Angled, - }; + typeRef.Include.InHeader |= IsIncludeInHeader(record); } + } - typeRef.Include.InHeader |= IsIncludeInHeader(record); + private bool ShouldIncludeTranslationUnit(TranslationUnit unit) + { + return !unit.IsSystemHeader && unit.IsValid && !unit.Ignore; } private string GetIncludePath(TranslationUnit translationUnit) @@ -168,7 +171,7 @@ namespace CppSharp.Generators.CLI return typedefType.Declaration.Type is BuiltinType; } - private bool IsIncludeInHeader(ASTRecord record) + public bool IsIncludeInHeader(ASTRecord record) { if (TranslationUnit == record.Value.Namespace.TranslationUnit) return false; @@ -198,7 +201,12 @@ namespace CppSharp.Generators.CLI var @ref = $"{keywords} {@class.Name};"; - GetTypeReference(@class).FowardReference = @ref; + var typeRef = GetTypeReference(@class); + + if (typeRef != null) + { + typeRef.FowardReference = @ref; + } return false; } @@ -217,7 +225,12 @@ namespace CppSharp.Generators.CLI var @ref = $"{enumKind} {@enum.Name}{@base};"; - GetTypeReference(@enum).FowardReference = @ref; + var typeRef = GetTypeReference(@enum); + + if (typeRef != null) + { + typeRef.FowardReference = @ref; + } return false; } diff --git a/src/Generator/Types/Std/Stdlib.cs b/src/Generator/Types/Std/Stdlib.cs index 0940c984..d3acad7f 100644 --- a/src/Generator/Types/Std/Stdlib.cs +++ b/src/Generator/Types/Std/Stdlib.cs @@ -690,13 +690,16 @@ namespace CppSharp.Types.Std { var typeRef = collector.GetTypeReference(loc.Value); - var include = new CInclude + if (typeRef != null) { - File = "cstddef", - Kind = CInclude.IncludeKind.Angled, - }; + var include = new CInclude + { + File = "cstddef", + Kind = CInclude.IncludeKind.Angled, + }; - typeRef.Include = include; + typeRef.Include = include; + } } } diff --git a/tests/CLI/CLI.Tests.cs b/tests/CLI/CLI.Tests.cs index 84f964f0..ae95948a 100644 --- a/tests/CLI/CLI.Tests.cs +++ b/tests/CLI/CLI.Tests.cs @@ -26,4 +26,13 @@ public class CLITests : GeneratorTestFixture Assert.AreEqual(EnumParam.E1, byRefEnumParam.GetPassedEnumParam(EnumParam.E1)); } } + + [Test] + public void GetEmployeeNameFromOrgTest() + { + using (EmployeeOrg org = new EmployeeOrg()) + { + Assert.AreEqual("Employee", org.Employee.Name); + } + } } \ No newline at end of file diff --git a/tests/CLI/CLI.cs b/tests/CLI/CLI.cs index 04c3b0a2..c929a3a3 100644 --- a/tests/CLI/CLI.cs +++ b/tests/CLI/CLI.cs @@ -1,9 +1,58 @@ using CppSharp.AST; +using CppSharp.AST.Extensions; using CppSharp.Generators; +using CppSharp.Passes; +using CppSharp.Types; using CppSharp.Utils; namespace CppSharp.Tests { + [TypeMap("IgnoredClassTemplateForEmployee")] + public class IgnoredClassTemplateForEmployeeMap : TypeMap + { + public override Type CLISignatureType(TypePrinterContext ctx) + { + return new CustomType("CLI::Employee^"); + } + + public override void CLIMarshalToManaged(MarshalContext ctx) + { + ctx.Return.Write($"gcnew CLI::Employee({ctx.ReturnVarName}.m_employee)"); + } + } + + public class CompleteIgnoredClassTemplateForEmployeeTypedefPass : TranslationUnitPass + { + public override bool VisitTypedefDecl(TypedefDecl typedef) + { + var templateType = GetDesugaredFinalPointeeElseType(typedef?.Type?.Desugar()) as TemplateSpecializationType; + bool isTemplateTypedef = IsTemplateTypedef(templateType?.Template?.OriginalName); + if (isTemplateTypedef) + { + Class @class; + if (templateType.TryGetClass(out @class)) + { + @class.IsIncomplete = false; + return true; + } + } + + return base.VisitTypedefDecl(typedef); + } + + private bool IsTemplateTypedef(string templateName) + { + return !string.IsNullOrEmpty(templateName) && "IgnoredClassTemplateForEmployee" == templateName; + } + + public Type GetDesugaredFinalPointeeElseType(Type t) + { + Type finalPointee = t.GetFinalPointee(); + + return finalPointee != null ? finalPointee.Desugar() : t; + } + } + public class CLITestsGenerator : GeneratorTest { public CLITestsGenerator(GeneratorKind kind) @@ -22,6 +71,11 @@ namespace CppSharp.Tests { } + public override void SetupPasses(Driver driver) + { + driver.AddTranslationUnitPass(new CompleteIgnoredClassTemplateForEmployeeTypedefPass()); + } + public static void Main(string[] args) { ConsoleDriver.Run(new CLITestsGenerator(GeneratorKind.CLI)); diff --git a/tests/CLI/CLI.h b/tests/CLI/CLI.h index ed99f161..4d5bc0ef 100644 --- a/tests/CLI/CLI.h +++ b/tests/CLI/CLI.h @@ -1,5 +1,8 @@ #include "../Tests.h" +#include "UseTemplateTypeFromIgnoredClassTemplate/Employee.h" +#include "UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h" + #include // Tests for C++ types diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp new file mode 100644 index 00000000..bebfadf0 --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp @@ -0,0 +1,6 @@ +#include "Employee.h" + +std::string Employee::GetName() +{ + return "Employee"; +} \ No newline at end of file diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h new file mode 100644 index 00000000..daabcac3 --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h @@ -0,0 +1,10 @@ +#pragma once + +#include "../../Tests.h" +#include + +class DLL_API Employee +{ +public: + virtual std::string GetName(); +}; \ No newline at end of file diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h new file mode 100644 index 00000000..ac9e4c83 --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h @@ -0,0 +1,4 @@ +#include "IgnoredClassTemplateForEmployee.h" + +class Employee; +typedef IgnoredClassTemplateForEmployee EmployeeTypedef; diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp new file mode 100644 index 00000000..86b7332e --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp @@ -0,0 +1,13 @@ + #include "EmployeeOrg.h" + +#include "Employee.h" + +EmployeeTypedef EmployeeOrg::GetEmployee() +{ + return IgnoredClassTemplateForEmployee(new Employee()); +} + +void EmployeeOrg::DoSomething() +{ + +} \ No newline at end of file diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h new file mode 100644 index 00000000..b1bcc40e --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h @@ -0,0 +1,13 @@ +#pragma once + +#include "../../Tests.h" + +#include "EmployeeForwardDecl.h" + +class DLL_API EmployeeOrg +{ +public: + void DoSomething(); + + EmployeeTypedef GetEmployee(); +}; \ No newline at end of file diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h new file mode 100644 index 00000000..25635f1e --- /dev/null +++ b/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h @@ -0,0 +1,13 @@ +#pragma once + +template +class IgnoredClassTemplateForEmployee +{ +public: + IgnoredClassTemplateForEmployee(EmployeeT* employee) + : m_employee(employee) + { + } + + EmployeeT* m_employee; +}; \ No newline at end of file diff --git a/tests/CLI/premake4.lua b/tests/CLI/premake4.lua index 87cd8296..4e3da006 100644 --- a/tests/CLI/premake4.lua +++ b/tests/CLI/premake4.lua @@ -1,2 +1,2 @@ group "Tests/CLI" - SetupTestCLI("CLI") \ No newline at end of file + SetupTestCLI("CLI", { "Employee", "EmployeeOrg" }) \ No newline at end of file