From 61c6047801c27e63bdc538f072452b77ae5c9b04 Mon Sep 17 00:00:00 2001 From: Nazar Kacharaba Date: Sat, 8 Jul 2023 14:32:00 +0300 Subject: [PATCH] Generate forward declaration for inner classes when they are actually used. --- CHANGELOG.md | 1 + .../gluecodium/generator/cpp/CppGenerator.kt | 17 +++-- .../generator/cpp/CppGeneratorPredicates.kt | 33 +++++++++- .../resources/templates/cpp/CppClass.mustache | 4 ++ .../input/InnerClassForwardDeclarations.lime | 22 ++++++- .../forward/InnerClassForwardDeclarations.h | 66 ++++++++++++++++--- 6 files changed, 121 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d87d573b..bc9b81df0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Bug fixes: * Fixed documentation references to constructors in Java. + * Added forward declaration for inner interfaces and classes. ## 13.6.1 ### Bug fixes: diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGenerator.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGenerator.kt index 0f2fc51c69..8abe5cc80f 100644 --- a/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGenerator.kt +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGenerator.kt @@ -32,7 +32,6 @@ import com.here.gluecodium.generator.common.NameHelper import com.here.gluecodium.generator.common.NameResolver import com.here.gluecodium.generator.common.nameRuleSetFromConfig import com.here.gluecodium.generator.common.templates.TemplateEngine -import com.here.gluecodium.generator.cpp.CppGeneratorPredicates.predicates import com.here.gluecodium.model.lime.LimeAttributeType.CPP import com.here.gluecodium.model.lime.LimeAttributeType.EQUATABLE import com.here.gluecodium.model.lime.LimeConstant @@ -123,10 +122,11 @@ internal class CppGenerator : Generator { .filter { it.external?.cpp == null } .map { it.fullName } .toSet() + val predicates = CppGeneratorPredicates(filteredModel.referenceMap).predicates val generatedFiles = filteredModel.topElements.flatMap { val fileName = nameRules.getOutputFilePath(it) - generateCode(it, fileName, includeResolver, nameResolver, fullNameResolver, signatureResolver, allErrorEnums) + generateCode(it, fileName, includeResolver, nameResolver, fullNameResolver, signatureResolver, allErrorEnums, predicates) } + COMMON_HEADERS.map { generateHelperFile(it, "include", ".h") } + COMMON_IMPLS.map { generateHelperFile(it, "src", ".cpp") } + generateExportHelperFile(exportCommonName, "Common", GeneratedFile.SourceSet.COMMON) + @@ -146,7 +146,8 @@ internal class CppGenerator : Generator { nameResolver: CppNameResolver, fullNameResolver: CppFullNameResolver, signatureResolver: CppSignatureResolver, - allErrorEnums: Set + allErrorEnums: Set, + predicates: Map Boolean> ): List { val allTypes = LimeTypeHelper.getAllTypes(rootElement) @@ -180,13 +181,13 @@ internal class CppGenerator : Generator { val headerIncludesCollector = CppHeaderIncludesCollector(includeResolver, allErrorEnums) val headerIncludes = headerIncludesCollector.collectImports(rootElement) + exportInclude templateData["functionUsings"] = collectFunctionUsings(rootElement, signatureResolver) - result += generateHeader(rootElement, nameResolvers, fileName, templateData, headerIncludes) + result += generateHeader(rootElement, nameResolvers, fileName, templateData, headerIncludes, predicates) } if (needsImplementation) { val implIncludesCollector = CppImplIncludesCollector(includeResolver, allErrorEnums) val implementationIncludes = implIncludesCollector.collectImports(rootElement) + createSelfInclude(rootElement, needsHeader, fileName) - result += generateImplementation(rootElement, nameResolvers, implementationIncludes, templateData, fileName) + result += generateImplementation(rootElement, nameResolvers, implementationIncludes, templateData, fileName, predicates) } return result @@ -206,7 +207,8 @@ internal class CppGenerator : Generator { nameResolvers: Map, implementationIncludes: List, generalData: Map, - fileName: String + fileName: String, + predicates: Map Boolean> ): GeneratedFile { val templateData = generalData + mapOf( "includes" to implementationIncludes.distinct().sorted(), @@ -223,7 +225,8 @@ internal class CppGenerator : Generator { nameResolvers: Map, fileName: String, generalData: Map, - headerIncludes: List + headerIncludes: List, + predicates: Map Boolean> ): GeneratedFile { val absolutePath = Paths.get(GENERATOR_NAME, "include", fileName) val headerFileName = "$absolutePath.h" diff --git a/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGeneratorPredicates.kt b/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGeneratorPredicates.kt index 85a43736f9..de0822c18e 100644 --- a/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGeneratorPredicates.kt +++ b/gluecodium/src/main/java/com/here/gluecodium/generator/cpp/CppGeneratorPredicates.kt @@ -23,16 +23,19 @@ import com.here.gluecodium.generator.common.CommonGeneratorPredicates import com.here.gluecodium.model.lime.LimeAttributeType import com.here.gluecodium.model.lime.LimeContainer import com.here.gluecodium.model.lime.LimeContainerWithInheritance +import com.here.gluecodium.model.lime.LimeElement import com.here.gluecodium.model.lime.LimeField import com.here.gluecodium.model.lime.LimeFunction +import com.here.gluecodium.model.lime.LimeNamedElement import com.here.gluecodium.model.lime.LimeStruct import com.here.gluecodium.model.lime.LimeType +import com.here.gluecodium.model.lime.LimeTypeHelper import com.here.gluecodium.model.lime.LimeTypeRef /** * List of predicates used by `ifPredicate`/`unlessPredicate` template helpers in C++ generator. */ -internal object CppGeneratorPredicates { +internal class CppGeneratorPredicates(private val referenceMap: Map) { val predicates = mapOf( "needsRefSuffix" to { limeTypeRef: Any -> limeTypeRef is LimeTypeRef && CppNameResolver.needsRefSuffix(limeTypeRef) @@ -101,10 +104,27 @@ internal object CppGeneratorPredicates { else -> true } }, + "isUsedInAnotherInnerClasses" to fun(limeField: Any): Boolean { + if (limeField !is LimeContainer || !limeField.path.hasParent) return false + val parent = referenceMap[limeField.path.parent.toAmbiguousString()] + if (parent !is LimeContainerWithInheritance) return false + + return (parent.interfaces + parent.classes) + .filter { it != limeField } + .map { InnerClassForwardDeclarationCollection.collectImports(it) } + .any { it.contains(limeField.fullName) } + }, "needsInnerForwardDeclarations" to fun(limeField: Any): Boolean { if (limeField !is LimeContainer) return false - return limeField.classes.size + limeField.interfaces.size > 0 - }, + + val containers = limeField.interfaces + limeField.classes + val typesUsedInTheClass = containers + .associateWith { InnerClassForwardDeclarationCollection.collectImports(it) } + + return containers.any { container -> + typesUsedInTheClass.filterKeys { it != container }.values.flatten().contains(container.fullName) + } + } ) private fun needsNotNullComment(limeTypeRef: LimeTypeRef) = @@ -119,4 +139,11 @@ internal object CppGeneratorPredicates { val typesToVisit = leafType.fields.map { it.typeRef.type.actualType }.distinct() - visitedTypes return typesToVisit.flatMap { getAllFieldTypesRec(it, visitedTypes) } + leafType } + + private object InnerClassForwardDeclarationCollection : CppImportsCollector() { + override fun collectImports(limeElement: LimeNamedElement): List { + val allTypes = LimeTypeHelper.getAllTypes(limeElement) + return collectTypeRefs(allTypes).map { it.elementFullName } + } + } } diff --git a/gluecodium/src/main/resources/templates/cpp/CppClass.mustache b/gluecodium/src/main/resources/templates/cpp/CppClass.mustache index 34545d9897..71b2382101 100644 --- a/gluecodium/src/main/resources/templates/cpp/CppClass.mustache +++ b/gluecodium/src/main/resources/templates/cpp/CppClass.mustache @@ -29,10 +29,14 @@ public: {{#ifPredicate "needsInnerForwardDeclarations"}} public: {{#this.classes}} +{{#ifPredicate "isUsedInAnotherInnerClasses"}} class {{this.name}}; +{{/ifPredicate}} {{/this.classes}} {{#this.interfaces}} +{{#ifPredicate "isUsedInAnotherInnerClasses"}} class {{this.name}}; +{{/ifPredicate}} {{/this.interfaces}} {{/ifPredicate}} diff --git a/gluecodium/src/test/resources/smoke/instances/input/InnerClassForwardDeclarations.lime b/gluecodium/src/test/resources/smoke/instances/input/InnerClassForwardDeclarations.lime index f541ff2eb2..4c08659ffe 100644 --- a/gluecodium/src/test/resources/smoke/instances/input/InnerClassForwardDeclarations.lime +++ b/gluecodium/src/test/resources/smoke/instances/input/InnerClassForwardDeclarations.lime @@ -17,11 +17,27 @@ package smoke.forward class InnerClassForwardDeclarations { @Internal - interface InnerInterface { + interface InnerInterface1 { } - open class InnerClass { + interface InnerInterface2 { + } + + interface InnerInterface3 { + } + + open class InnerClass1 { @Internal - fun getInnerInterface() : InnerInterface + fun getInnerInterface() : InnerInterface1 + } + + class InnerClass2 { + class InnerInnerClass1 { + fun foo() : InnerInnerClass2 + } + + class InnerInnerClass2 { + fun bar(arg: InnerInterface2) + } } } diff --git a/gluecodium/src/test/resources/smoke/instances/output/cpp/include/smoke/forward/InnerClassForwardDeclarations.h b/gluecodium/src/test/resources/smoke/instances/output/cpp/include/smoke/forward/InnerClassForwardDeclarations.h index 4235f291a7..cbb92670ae 100644 --- a/gluecodium/src/test/resources/smoke/instances/output/cpp/include/smoke/forward/InnerClassForwardDeclarations.h +++ b/gluecodium/src/test/resources/smoke/instances/output/cpp/include/smoke/forward/InnerClassForwardDeclarations.h @@ -18,28 +18,76 @@ class _GLUECODIUM_CPP_EXPORT InnerClassForwardDeclarations { virtual ~InnerClassForwardDeclarations() = 0; public: - class InnerClass; - class InnerInterface; + class InnerInterface1; + class InnerInterface2; public: - class _GLUECODIUM_CPP_EXPORT InnerClass { + class _GLUECODIUM_CPP_EXPORT InnerClass1 { public: - InnerClass(); - virtual ~InnerClass() = 0; + InnerClass1(); + virtual ~InnerClass1() = 0; public: /** * * \return @NotNull */ - virtual ::std::shared_ptr< ::smoke::forward::InnerClassForwardDeclarations::InnerInterface > get_inner_interface( ) = 0; + virtual ::std::shared_ptr< ::smoke::forward::InnerClassForwardDeclarations::InnerInterface1 > get_inner_interface( ) = 0; }; - class _GLUECODIUM_CPP_EXPORT InnerInterface { + class _GLUECODIUM_CPP_EXPORT InnerClass2 { public: - InnerInterface(); - virtual ~InnerInterface() = 0; + InnerClass2(); + virtual ~InnerClass2() = 0; + public: + class InnerInnerClass2; + + public: + class _GLUECODIUM_CPP_EXPORT InnerInnerClass1 { + public: + InnerInnerClass1(); + virtual ~InnerInnerClass1() = 0; + + public: + /** + * + * \return @NotNull + */ + virtual ::std::shared_ptr< ::smoke::forward::InnerClassForwardDeclarations::InnerClass2::InnerInnerClass2 > foo( ) = 0; + }; + + class _GLUECODIUM_CPP_EXPORT InnerInnerClass2 { + public: + InnerInnerClass2(); + virtual ~InnerInnerClass2() = 0; + + public: + /** + * + * \param[in] arg @NotNull + */ + virtual void bar( const ::std::shared_ptr< ::smoke::forward::InnerClassForwardDeclarations::InnerInterface2 >& arg ) = 0; + }; + + }; + + class _GLUECODIUM_CPP_EXPORT InnerInterface1 { + public: + InnerInterface1(); + virtual ~InnerInterface1() = 0; + }; + + class _GLUECODIUM_CPP_EXPORT InnerInterface2 { + public: + InnerInterface2(); + virtual ~InnerInterface2() = 0; + }; + + class _GLUECODIUM_CPP_EXPORT InnerInterface3 { + public: + InnerInterface3(); + virtual ~InnerInterface3() = 0; }; };