diff options
Diffstat (limited to 'tools/codegen')
5 files changed, 138 insertions, 104 deletions
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt index 5061be2091e5..92da9dab863b 100644 --- a/tools/codegen/src/com/android/codegen/ClassInfo.kt +++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt @@ -38,6 +38,11 @@ open class ClassInfo(val sourceLines: List<String>) { val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration) .implementedTypes.map { it.asString() } + val superClass = run { + val superClasses = (fileAst.types[0] as ClassOrInterfaceDeclaration).extendedTypes + if (superClasses.isNonEmpty) superClasses[0] else null + } + val ClassName = classAst.nameAsString private val genericArgsAst = classAst.typeParameters val genericArgs = if (genericArgsAst.isEmpty()) "" else { diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt index 1f0d4b8a7ec9..bd72d9e7ec21 100644 --- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt +++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt @@ -1,6 +1,7 @@ package com.android.codegen import com.github.javaparser.ast.Modifier +import com.github.javaparser.ast.body.CallableDeclaration import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration import com.github.javaparser.ast.body.TypeDeclaration import com.github.javaparser.ast.expr.* @@ -37,6 +38,7 @@ class ClassPrinter( val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") } val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") } val Parcelable by lazy { classRef("android.os.Parcelable") } + val Parcel by lazy { classRef("android.os.Parcel") } val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") } init { @@ -354,7 +356,9 @@ class ClassPrinter( } fun hasMethod(name: String, vararg argTypes: String): Boolean { - return classAst.methods.any { + val members: List<CallableDeclaration<*>> = + if (name == ClassName) classAst.constructors else classAst.methods + return members.any { it.name.asString() == name && it.parameters.map { it.type.asString() } == argTypes.toList() } @@ -365,6 +369,10 @@ class ClassPrinter( .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) } .filter { hasMethod("lazyInit${it.NameUpperCamel}") } + val extendsParcelableClass by lazy { + Parcelable !in superInterfaces && superClass != null + } + init { val builderFactoryOverride = classAst.methods.find { it.isStatic && it.nameAsString == "builder" diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index 865340566019..5a95676c1dc8 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -422,6 +422,10 @@ fun ClassPrinter.generateParcelable() { +"// void parcelFieldName(Parcel dest, int flags) { ... }" +"" + if (extendsParcelableClass) { + +"super.writeToParcel(dest, flags);\n" + } + if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { +"$flagStorageType flg = 0;" booleanFields.forEachApply { @@ -463,6 +467,123 @@ fun ClassPrinter.generateParcelable() { +"" } + if (!hasMethod(ClassName, Parcel)) { + val visibility = if (classAst.isFinal) "/* package-private */" else "protected" + + +"/** @hide */" + +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})" + +GENERATED_MEMBER_HEADER + "$visibility $ClassName($Parcel in) {" { + +"// You can override field unparcelling by defining methods like:" + +"// static FieldType unparcelFieldName(Parcel in) { ... }" + +"" + + if (extendsParcelableClass) { + +"super(in);\n" + } + + if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { + +"$flagStorageType flg = in.read$FlagStorageType();" + } + booleanFields.forEachApply { + +"$Type $_name = (flg & $fieldBit) != 0;" + } + nonBooleanFields.forEachApply { + + // Handle customized parceling + val customParcellingMethod = "unparcel$NameUpperCamel" + if (hasMethod(customParcellingMethod, Parcel)) { + +"$Type $_name = $customParcellingMethod(in);" + } else if (customParcellingClass != null) { + +"$Type $_name = $sParcelling.unparcel(in);" + } else if (hasAnnotation("@$DataClassEnum")) { + val ordinal = "${_name}Ordinal" + +"int $ordinal = in.readInt();" + +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];" + } else { + val methodArgs = mutableListOf<String>() + + // Create container if any + val containerInitExpr = when { + FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" + FieldClass == "List" || FieldClass == "ArrayList" -> + "new ${classRef("java.util.ArrayList")}<>()" + else -> "" + } + val passContainer = containerInitExpr.isNotEmpty() + + // nullcheck + + // "FieldType fieldName = (FieldType)" + if (passContainer) { + methodArgs.add(_name) + !"$Type $_name = " + if (mayBeNull) { + +"null;" + !"if ((flg & $fieldBit) != 0) {" + pushIndent() + +"" + !"$_name = " + } + +"$containerInitExpr;" + } else { + !"$Type $_name = " + if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : " + if (ParcelMethodsSuffix == "StrongInterface") { + !"$FieldClass.Stub.asInterface(" + } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && + (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && + ParcelMethodsSuffix != "Parcelable") { + !"($FieldClass) " + } + } + + // Determine method args + when { + ParcelMethodsSuffix == "Parcelable" -> + methodArgs += "$FieldClass.class.getClassLoader()" + ParcelMethodsSuffix == "SparseArray" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" + ParcelMethodsSuffix == "TypedObject" -> + methodArgs += "$FieldClass.CREATOR" + ParcelMethodsSuffix == "TypedArray" -> + methodArgs += "$FieldInnerClass.CREATOR" + ParcelMethodsSuffix == "Map" -> + methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" + ParcelMethodsSuffix.startsWith("Parcelable") + || (isList || isArray) + && FieldInnerType !in PRIMITIVE_TYPES + "String" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" + } + + // ...in.readFieldType(args...); + when { + ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder" + isArray -> !"in.create$ParcelMethodsSuffix" + else -> !"in.read$ParcelMethodsSuffix" + } + !"(${methodArgs.joinToString(", ")})" + if (ParcelMethodsSuffix == "StrongInterface") !")" + +";" + + // Cleanup if passContainer + if (passContainer && mayBeNull) { + popIndent() + rmEmptyLine() + +"\n}" + } + } + } + + +"" + fields.forEachApply { + !"this." + generateSetFrom(_name) + } + + generateOnConstructedCallback() + } + } + if (classAst.fields.none { it.variables[0].nameAsString == "CREATOR" }) { val Creator = classRef("android.os.Parcelable.Creator") @@ -477,107 +598,8 @@ fun ClassPrinter.generateParcelable() { } +"@Override" - +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})" "public $ClassName createFromParcel($Parcel in)" { - +"// You can override field unparcelling by defining methods like:" - +"// static FieldType unparcelFieldName(Parcel in) { ... }" - +"" - if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { - +"$flagStorageType flg = in.read$FlagStorageType();" - } - booleanFields.forEachApply { - +"$Type $_name = (flg & $fieldBit) != 0;" - } - nonBooleanFields.forEachApply { - - // Handle customized parceling - val customParcellingMethod = "unparcel$NameUpperCamel" - if (hasMethod(customParcellingMethod, Parcel)) { - +"$Type $_name = $customParcellingMethod(in);" - } else if (customParcellingClass != null) { - +"$Type $_name = $sParcelling.unparcel(in);" - } else if (hasAnnotation("@$DataClassEnum")) { - val ordinal = "${_name}Ordinal" - +"int $ordinal = in.readInt();" - +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];" - } else { - val methodArgs = mutableListOf<String>() - - // Create container if any - val containerInitExpr = when { - FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" - FieldClass == "List" || FieldClass == "ArrayList" -> - "new ${classRef("java.util.ArrayList")}<>()" - else -> "" - } - val passContainer = containerInitExpr.isNotEmpty() - - // nullcheck + - // "FieldType fieldName = (FieldType)" - if (passContainer) { - methodArgs.add(_name) - !"$Type $_name = " - if (mayBeNull) { - +"null;" - !"if ((flg & $fieldBit) != 0) {" - pushIndent() - +"" - !"$_name = " - } - +"$containerInitExpr;" - } else { - !"$Type $_name = " - if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : " - if (ParcelMethodsSuffix == "StrongInterface") { - !"$FieldClass.Stub.asInterface(" - } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && - (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && - ParcelMethodsSuffix != "Parcelable") { - !"($FieldClass) " - } - } - - // Determine method args - when { - ParcelMethodsSuffix == "Parcelable" -> - methodArgs += "$FieldClass.class.getClassLoader()" - ParcelMethodsSuffix == "SparseArray" -> - methodArgs += "$FieldInnerClass.class.getClassLoader()" - ParcelMethodsSuffix == "TypedObject" -> - methodArgs += "$FieldClass.CREATOR" - ParcelMethodsSuffix == "TypedArray" -> - methodArgs += "$FieldInnerClass.CREATOR" - ParcelMethodsSuffix == "Map" -> - methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" - ParcelMethodsSuffix.startsWith("Parcelable") - || (isList || isArray) - && FieldInnerType !in PRIMITIVE_TYPES + "String" -> - methodArgs += "$FieldInnerClass.class.getClassLoader()" - } - - // ...in.readFieldType(args...); - when { - ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder" - isArray -> !"in.create$ParcelMethodsSuffix" - else -> !"in.read$ParcelMethodsSuffix" - } - !"(${methodArgs.joinToString(", ")})" - if (ParcelMethodsSuffix == "StrongInterface") !")" - +";" - - // Cleanup if passContainer - if (passContainer && mayBeNull) { - popIndent() - rmEmptyLine() - +"\n}" - } - } - } - "return new $ClassType(" { - fields.forEachTrimmingTrailingComma { - +"$_name," - } - } + ";" + +"return new $ClassName(in);" } rmEmptyLine() } + ";" diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index 580467433756..c91eca94a9c0 100755 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt @@ -146,8 +146,7 @@ fun main(args: Array<String>) { generateConstructor("public") } else if (FeatureFlag.BUILDER() || FeatureFlag.COPY_CONSTRUCTOR() - || FeatureFlag.WITHERS() - || FeatureFlag.PARCELABLE()) { + || FeatureFlag.WITHERS()) { generateConstructor("/* package-private */") } if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor() diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 1cc7ef338cc3..a36f2c838787 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.4" +const val CODEGEN_VERSION = "1.0.5" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" |