summaryrefslogtreecommitdiff
path: root/tools/codegen/src/com/android/codegen/ClassPrinter.kt
diff options
context:
space:
mode:
authorEugene Susla <eugenesusla@google.com>2019-10-22 17:32:08 -0700
committerEugene Susla <eugenesusla@google.com>2019-11-01 17:53:56 +0000
commit322e8b17721a6956e00407e8d431ceecbd245b5c (patch)
tree9fe5a43411281cf93c377a2d6fcd326a299ec97e /tools/codegen/src/com/android/codegen/ClassPrinter.kt
parent4a0b1750ef697bb4f329a3beffe88bf46e1e6385 (diff)
[codegen] Support nested classes
Adds support for arbitrarily-nested @DataClasses Only static ones are supported for now See FileInfo for the main implementation piece Fixes: 139833958 Test: . frameworks/base/tests/Codegen/runTest.sh Change-Id: I31cd16969788c47003a7a15a3573a4bf623ab960
Diffstat (limited to 'tools/codegen/src/com/android/codegen/ClassPrinter.kt')
-rw-r--r--tools/codegen/src/com/android/codegen/ClassPrinter.kt282
1 files changed, 57 insertions, 225 deletions
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index bd72d9e7ec21..a4fd374d0c6e 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -11,36 +11,12 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType
* [ClassInfo] + utilities for printing out new class code with proper indentation and imports
*/
class ClassPrinter(
- source: List<String>,
- private val stringBuilder: StringBuilder,
- var cliArgs: Array<String>
-) : ClassInfo(source) {
+ classAst: ClassOrInterfaceDeclaration,
+ fileInfo: FileInfo
+) : ClassInfo(classAst, fileInfo), Printer<ClassPrinter>, ImportsProvider {
val GENERATED_MEMBER_HEADER by lazy { "@$GeneratedMember" }
- // Imports
- val NonNull by lazy { classRef("android.annotation.NonNull") }
- val NonEmpty by lazy { classRef("android.annotation.NonEmpty") }
- val Nullable by lazy { classRef("android.annotation.Nullable") }
- val TextUtils by lazy { classRef("android.text.TextUtils") }
- val LinkedHashMap by lazy { classRef("java.util.LinkedHashMap") }
- val Collections by lazy { classRef("java.util.Collections") }
- val Preconditions by lazy { classRef("com.android.internal.util.Preconditions") }
- val ArrayList by lazy { classRef("java.util.ArrayList") }
- val DataClass by lazy { classRef("com.android.internal.util.DataClass") }
- val DataClassEnum by lazy { classRef("com.android.internal.util.DataClass.Enum") }
- val ParcelWith by lazy { classRef("com.android.internal.util.DataClass.ParcelWith") }
- 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 Parcel by lazy { classRef("android.os.Parcel") }
- val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
-
init {
val fieldsWithMissingNullablity = fields.filter { field ->
!field.isPrimitive
@@ -60,50 +36,61 @@ class ClassPrinter(
}
}
- /**
- * Optionally shortens a class reference if there's a corresponding import present
- */
- fun classRef(fullName: String): String {
- if (cliArgs.contains(FLAG_NO_FULL_QUALIFIERS)) {
- return fullName.split(".").dropWhile { it[0].isLowerCase() }.joinToString(".")
- }
+ val cliArgs get() = fileInfo.cliArgs
- val pkg = fullName.substringBeforeLast(".")
- val simpleName = fullName.substringAfterLast(".")
- if (fileAst.imports.any { imprt ->
- imprt.nameAsString == fullName
- || (imprt.isAsterisk && imprt.nameAsString == pkg)
- }) {
- return simpleName
- } else {
- val outerClass = pkg.substringAfterLast(".", "")
- if (outerClass.firstOrNull()?.isUpperCase() == true) {
- return classRef(pkg) + "." + simpleName
- }
- }
- return fullName
- }
+ fun print() {
+ currentIndent = fileInfo.sourceLines
+ .find { "class $ClassName" in it }!!
+ .takeWhile { it.isWhitespace() }
+ .plus(INDENT_SINGLE)
- /** @see classRef */
- inline fun <reified T : Any> classRef(): String {
- return classRef(T::class.java.name)
- }
+ +fileInfo.generatedWarning
- /** @see classRef */
- fun memberRef(fullName: String): String {
- val className = fullName.substringBeforeLast(".")
- val methodName = fullName.substringAfterLast(".")
- return if (fileAst.imports.any {
- it.isStatic
- && (it.nameAsString == fullName
- || (it.isAsterisk && it.nameAsString == className))
- }) {
- className.substringAfterLast(".") + "." + methodName
- } else {
- classRef(className) + "." + methodName
+ if (FeatureFlag.CONST_DEFS()) generateConstDefs()
+
+
+ if (FeatureFlag.CONSTRUCTOR()) {
+ generateConstructor("public")
+ } else if (FeatureFlag.BUILDER()
+ || FeatureFlag.COPY_CONSTRUCTOR()
+ || FeatureFlag.WITHERS()) {
+ generateConstructor("/* package-private */")
}
+ if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
+
+ if (FeatureFlag.GETTERS()) generateGetters()
+ if (FeatureFlag.SETTERS()) generateSetters()
+ if (FeatureFlag.TO_STRING()) generateToString()
+ if (FeatureFlag.EQUALS_HASH_CODE()) generateEqualsHashcode()
+
+ if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
+
+ if (FeatureFlag.WITHERS()) generateWithers()
+
+ if (FeatureFlag.PARCELABLE()) generateParcelable()
+
+ if (FeatureFlag.BUILDER() && FeatureFlag.BUILD_UPON()) generateBuildUpon()
+ if (FeatureFlag.BUILDER()) generateBuilder()
+
+ if (FeatureFlag.AIDL()) fileInfo.generateAidl() //TODO guard against nested classes requesting aidl
+
+ generateMetadata(fileInfo.file)
+
+ +"""
+ //@formatter:on
+ $GENERATED_END
+
+ """
+
+ rmEmptyLine()
}
+ override var currentIndent: String
+ get() = fileInfo.currentIndent
+ set(value) { fileInfo.currentIndent = value }
+ override val stringBuilder get() = fileInfo.stringBuilder
+
+
val dataClassAnnotationFeatures = classAst.annotations
.find { it.nameAsString == DataClass }
?.let { it as? NormalAnnotationExpr }
@@ -143,7 +130,7 @@ class ClassPrinter(
|| onByDefault
FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
- FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
+ FeatureFlag.AIDL -> fileInfo.mainClass.nameAsString == ClassName && FeatureFlag.PARCELABLE()
FeatureFlag.IMPLICIT_NONNULL -> fields.any { it.isNullable }
&& fields.none { "@$NonNull" in it.annotations }
else -> onByDefault
@@ -163,162 +150,7 @@ class ClassPrinter(
}
}
- var currentIndent = INDENT_SINGLE
- private set
-
- fun pushIndent() {
- currentIndent += INDENT_SINGLE
- }
-
- fun popIndent() {
- currentIndent = currentIndent.substring(0, currentIndent.length - INDENT_SINGLE.length)
- }
-
- fun backspace() = stringBuilder.setLength(stringBuilder.length - 1)
- val lastChar get() = stringBuilder[stringBuilder.length - 1]
-
- private fun appendRaw(s: String) {
- stringBuilder.append(s)
- }
-
- fun append(s: String) {
- if (s.isBlank() && s != "\n") {
- appendRaw(s)
- } else {
- appendRaw(s.lines().map { line ->
- if (line.startsWith(" *")) line else line.trimStart()
- }.joinToString("\n$currentIndent"))
- }
- }
-
- fun appendSameLine(s: String) {
- while (lastChar.isWhitespace() || lastChar.isNewline()) {
- backspace()
- }
- appendRaw(s)
- }
-
- fun rmEmptyLine() {
- while (lastChar.isWhitespaceNonNewline()) backspace()
- if (lastChar.isNewline()) backspace()
- }
-
- /**
- * Syntactic sugar for:
- * ```
- * +"code()";
- * ```
- * to append the given string plus a newline
- */
- operator fun String.unaryPlus() = append("$this\n")
-
- /**
- * Syntactic sugar for:
- * ```
- * !"code()";
- * ```
- * to append the given string without a newline
- */
- operator fun String.not() = append(this)
-
- /**
- * Syntactic sugar for:
- * ```
- * ... {
- * ...
- * }+";"
- * ```
- * to append a ';' on same line after a block, and a newline afterwards
- */
- operator fun Unit.plus(s: String) {
- appendSameLine(s)
- +""
- }
-
- /**
- * A multi-purpose syntactic sugar for appending the given string plus anything generated in
- * the given [block], the latter with the appropriate deeper indent,
- * and resetting the indent back to original at the end
- *
- * Usage examples:
- *
- * ```
- * "if (...)" {
- * ...
- * }
- * ```
- * to append a corresponding if block appropriate indentation
- *
- * ```
- * "void foo(...)" {
- * ...
- * }
- * ```
- * similar to the previous one, plus an extra empty line after the function body
- *
- * ```
- * "void foo(" {
- * <args code>
- * }
- * ```
- * to use proper indentation for args code and close the bracket on same line at end
- *
- * ```
- * "..." {
- * ...
- * }
- * to use the correct indentation for inner code, resetting it at the end
- */
- inline operator fun String.invoke(block: ClassPrinter.() -> Unit) {
- if (this == " {") {
- appendSameLine(this)
- } else {
- append(this)
- }
- when {
- endsWith("(") -> {
- indentedBy(2, block)
- appendSameLine(")")
- }
- endsWith("{") || endsWith(")") -> {
- if (!endsWith("{")) appendSameLine(" {")
- indentedBy(1, block)
- +"}"
- if ((endsWith(") {") || endsWith(")") || this == " {")
- && !startsWith("synchronized")
- && !startsWith("switch")
- && !startsWith("if ")
- && !contains(" else ")
- && !contains("new ")
- && !contains("return ")) {
- +"" // extra line after function definitions
- }
- }
- else -> indentedBy(2, block)
- }
- }
-
- inline fun indentedBy(level: Int, block: ClassPrinter.() -> Unit) {
- append("\n")
- level times {
- append(INDENT_SINGLE)
- pushIndent()
- }
- block()
- level times { popIndent() }
- rmEmptyLine()
- +""
- }
- inline fun Iterable<FieldInfo>.forEachTrimmingTrailingComma(b: FieldInfo.() -> Unit) {
- forEachApply {
- b()
- if (isLast) {
- while (lastChar == ' ' || lastChar == '\n') backspace()
- if (lastChar == ',') backspace()
- }
- }
- }
inline operator fun <R> invoke(f: ClassPrinter.() -> R): R = run(f)
@@ -381,10 +213,10 @@ class ClassPrinter(
BuilderClass = (builderFactoryOverride.type as ClassOrInterfaceType).nameAsString
BuilderType = builderFactoryOverride.type.asString()
} else {
- val builderExtension = (fileAst.types
- + classAst.childNodes.filterIsInstance(TypeDeclaration::class.java)).find {
- it.nameAsString == CANONICAL_BUILDER_CLASS
- }
+ val builderExtension = classAst
+ .childNodes
+ .filterIsInstance(TypeDeclaration::class.java)
+ .find { it.nameAsString == CANONICAL_BUILDER_CLASS }
if (builderExtension != null) {
BuilderClass = BASE_BUILDER_CLASS
val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters