12259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar/* 22259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Copyright (C) 2016 The Android Open Source Project 32259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * 42259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 52259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * you may not use this file except in compliance with the License. 62259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * You may obtain a copy of the License at 72259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * 82259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 92259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * 102259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Unless required by applicable law or agreed to in writing, software 112259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 122259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * See the License for the specific language governing permissions and 142259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * limitations under the License. 152259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar */ 162259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar 17bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverettepackage androidx.room.solver 182259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar 19bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viveretteimport androidx.room.writer.ClassWriter 202259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyarimport com.google.common.annotations.VisibleForTesting 212259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyarimport com.squareup.javapoet.CodeBlock 22bdc4c86d3dff74f6634a38e2f7b316b0e823a2c8Alan Viverette 232259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar/** 242259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar * Defines a code generation scope where we can provide temporary variables, global variables etc 252259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar */ 266f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikasclass CodeGenScope(val writer: ClassWriter) { 278e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar private var tmpVarIndices = mutableMapOf<String, Int>() 286f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas private var builder: CodeBlock.Builder? = null 292259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar companion object { 308e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar const val TMP_VAR_DEFAULT_PREFIX = "_tmp" 31645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar const val CLASS_PROPERTY_PREFIX = "__" 322259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar @VisibleForTesting 336f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun _tmpVar(index: Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index) 346f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun _tmpVar(prefix: String, index: Int) = "$prefix${if (index == 0) "" else "_$index"}" 352259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar } 362259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar 376f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun builder(): CodeBlock.Builder { 382259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar if (builder == null) { 392259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar builder = CodeBlock.builder() 402259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar } 412259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar return builder!! 422259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar } 432259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar 446f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun getTmpVar(): String { 458e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar return getTmpVar(TMP_VAR_DEFAULT_PREFIX) 468e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar } 478e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar 486f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun getTmpVar(prefix: String): String { 498e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar if (!prefix.startsWith("_")) { 50645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar throw IllegalArgumentException("tmp variable prefixes should start with _") 51645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar } 52645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar if (prefix.startsWith(CLASS_PROPERTY_PREFIX)) { 53645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar throw IllegalArgumentException("cannot use $CLASS_PROPERTY_PREFIX for tmp variables") 548e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar } 558e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar val index = tmpVarIndices.getOrElse(prefix) { 0 } 568e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar val result = _tmpVar(prefix, index) 578e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar tmpVarIndices.put(prefix, index + 1) 588e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar return result 592259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar } 602259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar 612259e4dc433701d006db35df4c5e9f8d51e7d29bYigit Boyar fun generate() = builder().build().toString() 62d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar 63d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar /** 64d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar * copies all variable indices but excludes generated code. 65d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar */ 666f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun fork(): CodeGenScope { 67645abf12d5a13dae5c2271cedd0563a580871a2bYigit Boyar val forked = CodeGenScope(writer) 68d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar forked.tmpVarIndices.putAll(tmpVarIndices) 69d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar return forked 70d72e20e472815b7d0918e0d309cee48a71c7988bYigit Boyar } 71e2476a0cdc340c8071c938132b2c77b8349c5a01Yigit Boyar} 72