summaryrefslogtreecommitdiff
path: root/tools/codegen/src/com/android/codegen/ClassPrinter.kt
diff options
context:
space:
mode:
authorEugene Susla <eugenesusla@google.com>2019-07-25 14:05:12 -0700
committerEugene Susla <eugenesusla@google.com>2019-08-05 16:54:41 -0700
commit3156a4ce21cb4de46f84b8c7264a3dc31dd8db8b (patch)
treecf2a361a56d6f45de239da3ff5f4fa58e1d59431 /tools/codegen/src/com/android/codegen/ClassPrinter.kt
parent2eaec69928b0394b7e6979c71a707d1b2418365c (diff)
Addresses further review comments from ag/8000041
Including: - An API to opt out of Int/StringDefs generation on per-field basis - A way to customize Builder - Non-optional fields are passed in Builder constructor - Various adjustments to SampleDataclass examples, as requested Test: . $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/runTest.sh Change-Id: I32d2eec52f05d505ff07779d923e4793d3036579
Diffstat (limited to 'tools/codegen/src/com/android/codegen/ClassPrinter.kt')
-rw-r--r--tools/codegen/src/com/android/codegen/ClassPrinter.kt79
1 files changed, 73 insertions, 6 deletions
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index 33256b787964..f1645ea9a3bb 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -1,9 +1,9 @@
package com.android.codegen
+import com.github.javaparser.ast.Modifier
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
import com.github.javaparser.ast.body.TypeDeclaration
-import com.github.javaparser.ast.expr.BooleanLiteralExpr
-import com.github.javaparser.ast.expr.NormalAnnotationExpr
+import com.github.javaparser.ast.expr.*
import com.github.javaparser.ast.type.ClassOrInterfaceType
/**
@@ -32,10 +32,31 @@ class ClassPrinter(
val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") }
val Each by lazy { classRef("com.android.internal.util.DataClass.Each") }
val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") }
+ val DataClassSuppressConstDefs by lazy { classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
+ val DataClassSuppress by lazy { classRef("com.android.internal.util.DataClass.Suppress") }
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 UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
+ init {
+ val fieldsWithMissingNullablity = fields.filter { field ->
+ !field.isPrimitive
+ && Modifier.TRANSIENT !in field.fieldAst.modifiers
+ && "@$Nullable" !in field.annotations
+ && "@$NonNull" !in field.annotations
+ }
+ if (fieldsWithMissingNullablity.isNotEmpty()) {
+ abort("Non-primitive fields must have @$Nullable or @$NonNull annotation.\n" +
+ "Missing nullability annotations on: "
+ + fieldsWithMissingNullablity.joinToString(", ") { it.name })
+ }
+
+ if (!classAst.isFinal &&
+ classAst.extendedTypes.any { it.nameAsString == Parcelable }) {
+ abort("Parcelable classes must be final")
+ }
+ }
/**
* Optionally shortens a class reference if there's a corresponding import present
@@ -54,7 +75,7 @@ class ClassPrinter(
return simpleName
} else {
val outerClass = pkg.substringAfterLast(".", "")
- if (outerClass.firstOrNull()?.isUpperCase() ?: false) {
+ if (outerClass.firstOrNull()?.isUpperCase() == true) {
return classRef(pkg) + "." + simpleName
}
}
@@ -89,7 +110,9 @@ class ClassPrinter(
?.toMap()
?: emptyMap()
- val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, Each, UnsupportedAppUsage)
+ val internalAnnotations = setOf(ParcelWith, DataClassEnum, PluralOf, UnsupportedAppUsage,
+ DataClassSuppressConstDefs)
+ val knownNonValidationAnnotations = internalAnnotations + Each + Nullable
/**
* @return whether the given feature is enabled
@@ -109,7 +132,9 @@ class ClassPrinter(
return when (this) {
FeatureFlag.SETTERS ->
!FeatureFlag.CONSTRUCTOR() && !FeatureFlag.BUILDER() && fields.any { !it.isFinal }
- FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS) || onByDefault
+ FeatureFlag.BUILDER -> cliArgs.contains(FLAG_BUILDER_PROTECTED_SETTERS)
+ || fields.any { it.hasDefault }
+ || onByDefault
FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
@@ -287,6 +312,48 @@ class ClassPrinter(
var BuilderClass = CANONICAL_BUILDER_CLASS
var BuilderType = BuilderClass + genericArgs
+ val customBaseBuilderAst: ClassOrInterfaceDeclaration? by lazy {
+ nestedClasses.find { it.nameAsString == BASE_BUILDER_CLASS }
+ }
+
+ val suppressedMembers by lazy {
+ getSuppressedMembers(classAst)
+ }
+ val builderSuppressedMembers by lazy {
+ getSuppressedMembers(customBaseBuilderAst)
+ }
+
+ private fun getSuppressedMembers(clazz: ClassOrInterfaceDeclaration?): List<String> {
+ return clazz
+ ?.annotations
+ ?.find { it.nameAsString == DataClassSuppress }
+ ?.as_<SingleMemberAnnotationExpr>()
+ ?.memberValue
+ ?.run {
+ when (this) {
+ is ArrayInitializerExpr -> values.map { it.asLiteralStringValueExpr().value }
+ is StringLiteralExpr -> listOf(value)
+ else -> abort("Can't parse annotation arg: $this")
+ }
+ }
+ ?: emptyList()
+ }
+
+ fun isMethodGenerationSuppressed(name: String, vararg argTypes: String): Boolean {
+ return name in suppressedMembers || hasMethod(name, *argTypes)
+ }
+
+ fun hasMethod(name: String, vararg argTypes: String): Boolean {
+ return classAst.methods.any {
+ it.name.asString() == name &&
+ it.parameters.map { it.type.asString() } == argTypes.toList()
+ }
+ }
+
+ val lazyTransientFields = classAst.fields
+ .filter { it.isTransient && !it.isStatic }
+ .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
+ .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
init {
val builderFactoryOverride = classAst.methods.find {
@@ -301,7 +368,7 @@ class ClassPrinter(
it.nameAsString == CANONICAL_BUILDER_CLASS
}
if (builderExtension != null) {
- BuilderClass = GENERATED_BUILDER_CLASS
+ BuilderClass = BASE_BUILDER_CLASS
val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters
BuilderType = if (tp.isEmpty()) BuilderClass
else "$BuilderClass<${tp.map { it.nameAsString }.joinToString(", ")}>"