1 /* <lambda>null2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.room.compiler.codegen.java 18 19 import androidx.room.compiler.codegen.JCodeBlock 20 import androidx.room.compiler.codegen.JCodeBlockBuilder 21 import androidx.room.compiler.codegen.XAnnotationSpec 22 import androidx.room.compiler.codegen.XCodeBlock 23 import androidx.room.compiler.codegen.XFunSpec 24 import androidx.room.compiler.codegen.XMemberName 25 import androidx.room.compiler.codegen.XName 26 import androidx.room.compiler.codegen.XPropertySpec 27 import androidx.room.compiler.codegen.XSpec 28 import androidx.room.compiler.codegen.XTypeName 29 import androidx.room.compiler.codegen.XTypeSpec 30 import androidx.room.compiler.codegen.impl.XAnnotationSpecImpl 31 import androidx.room.compiler.codegen.impl.XCodeBlockImpl 32 import androidx.room.compiler.codegen.impl.XFunSpecImpl 33 import androidx.room.compiler.codegen.impl.XPropertySpecImpl 34 import androidx.room.compiler.codegen.impl.XTypeSpecImpl 35 36 internal class JavaCodeBlock(internal val actual: JCodeBlock) : XSpec(), XCodeBlock { 37 38 internal class Builder(internal val actual: JCodeBlockBuilder) : 39 XSpec.Builder(), XCodeBlock.Builder { 40 41 override fun add(code: XCodeBlock) = apply { 42 require(code is XCodeBlockImpl) 43 actual.add(code.java.actual) 44 } 45 46 override fun add(format: String, vararg args: Any?) = apply { 47 actual.add(formatString(format), *formatArgs(args)) 48 } 49 50 override fun addStatement(format: String, vararg args: Any?) = apply { 51 actual.addStatement(formatString(format), *formatArgs(args)) 52 } 53 54 override fun addLocalVariable( 55 name: String, 56 typeName: XTypeName, 57 isMutable: Boolean, 58 assignExpr: XCodeBlock? 59 ) = apply { 60 val finalKeyword = if (isMutable) "" else "final " 61 if (assignExpr != null) { 62 addStatement("$finalKeyword%T %L = %L", typeName, name, assignExpr) 63 } else { 64 addStatement("$finalKeyword%T %L", typeName, name) 65 } 66 } 67 68 override fun beginControlFlow(controlFlow: String, vararg args: Any?) = apply { 69 actual.beginControlFlow(formatString(controlFlow), *formatArgs(args)) 70 } 71 72 override fun nextControlFlow(controlFlow: String, vararg args: Any?) = apply { 73 actual.nextControlFlow(formatString(controlFlow), *formatArgs(args)) 74 } 75 76 override fun endControlFlow() = apply { actual.endControlFlow() } 77 78 override fun indent() = apply { actual.indent() } 79 80 override fun unindent() = apply { actual.unindent() } 81 82 override fun build() = JavaCodeBlock(actual.build()) 83 84 // Converts '%' place holders to '$' for JavaPoet 85 private fun formatString(format: String): String { 86 // Replace KPoet's member name placeholder for a JPoet literal for a XMemberName arg. 87 return format 88 .replace("%M", "\$L") 89 // TODO(b/247241415): Very simple replace for now, but this will not work when 90 // emitting modulo expressions! 91 .replace('%', '$') 92 } 93 94 // Unwraps room.compiler.codegen types to their JavaPoet actual 95 // TODO(b/247242375): Consider improving by wrapping args. 96 private fun formatArgs(args: Array<out Any?>): Array<Any?> { 97 return Array(args.size) { index -> 98 when (val arg = args[index]) { 99 is XTypeName -> arg.java 100 is XMemberName -> arg.java 101 is XName -> arg.java 102 is XTypeSpec -> (arg as XTypeSpecImpl).java.actual 103 is XPropertySpec -> (arg as XPropertySpecImpl).java.actual 104 is XFunSpec -> (arg as XFunSpecImpl).java.actual 105 is XCodeBlock -> (arg as XCodeBlockImpl).java.actual 106 is XAnnotationSpec -> (arg as XAnnotationSpecImpl).java.actual 107 is XTypeSpec.Builder, 108 is XPropertySpec.Builder, 109 is XFunSpec.Builder, 110 is XCodeBlock.Builder, 111 is XAnnotationSpec.Builder -> 112 error("Found builder, ${arg.javaClass}. Did you forget to call .build()?") 113 else -> arg 114 } 115 } 116 } 117 } 118 } 119