1 /* 2 * Copyright (C) 2021 The Dagger Authors. 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 dagger.hilt.processor.internal.root.ir 18 19 import kotlin.jvm.Throws 20 21 // Validates roots being processed. 22 object AggregatedRootIrValidator { 23 @JvmStatic 24 @Throws(InvalidRootsException::class) rootsToProcessnull25 fun rootsToProcess( 26 isCrossCompilationRootValidationDisabled: Boolean, 27 processedRoots: Set<ProcessedRootSentinelIr>, 28 aggregatedRoots: Set<AggregatedRootIr> 29 ): Set<AggregatedRootIr> { 30 val processedRootNames = processedRoots.flatMap { it.roots }.toSet() 31 val rootsToProcess = 32 aggregatedRoots.filterNot { processedRootNames.contains(it.root.canonicalName()) }.sortedBy { 33 it.root.canonicalName() 34 } 35 val testRootsToProcess = rootsToProcess.filter { it.isTestRoot } 36 val appRootsToProcess = rootsToProcess - testRootsToProcess 37 fun Collection<AggregatedRootIr>.rootsToString() = map { it.root }.joinToString() 38 if (appRootsToProcess.size > 1) { 39 throw InvalidRootsException( 40 "Cannot process multiple app roots in the same compilation unit: " + 41 appRootsToProcess.rootsToString() 42 ) 43 } 44 if (testRootsToProcess.isNotEmpty() && appRootsToProcess.isNotEmpty()) { 45 throw InvalidRootsException( 46 """ 47 Cannot process test roots and app roots in the same compilation unit: 48 App root in this compilation unit: ${appRootsToProcess.rootsToString()} 49 Test roots in this compilation unit: ${testRootsToProcess.rootsToString()} 50 """.trimIndent() 51 ) 52 } 53 // Perform validation across roots previous compilation units. 54 if (!isCrossCompilationRootValidationDisabled) { 55 val alreadyProcessedTestRoots = 56 aggregatedRoots.filter { 57 it.isTestRoot && processedRootNames.contains(it.root.canonicalName()) 58 } 59 // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this. 60 if (alreadyProcessedTestRoots.isNotEmpty() && rootsToProcess.isNotEmpty()) { 61 throw InvalidRootsException( 62 """ 63 Cannot process new roots when there are test roots from a previous compilation unit: 64 Test roots from previous compilation unit: ${alreadyProcessedTestRoots.rootsToString()} 65 All roots from this compilation unit: ${rootsToProcess.rootsToString()} 66 """.trimIndent() 67 ) 68 } 69 70 val alreadyProcessedAppRoots = 71 aggregatedRoots.filter { 72 !it.isTestRoot && processedRootNames.contains(it.root.canonicalName()) 73 } 74 if (alreadyProcessedAppRoots.isNotEmpty() && appRootsToProcess.isNotEmpty()) { 75 throw InvalidRootsException( 76 """ 77 Cannot process new app roots when there are app roots from a previous compilation unit: 78 App roots in previous compilation unit: ${alreadyProcessedAppRoots.rootsToString()} 79 App roots in this compilation unit: ${appRootsToProcess.rootsToString()} 80 """.trimIndent() 81 ) 82 } 83 } 84 return rootsToProcess.toSet() 85 } 86 } 87 88 // An exception thrown when root validation fails. 89 class InvalidRootsException(msg: String) : Exception(msg) 90