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 = aggregatedRoots 32 .filterNot { processedRootNames.contains(it.root) } 33 .sortedBy { it.root.toString() } 34 val testRootsToProcess = rootsToProcess.filter { it.isTestRoot } 35 val appRootsToProcess = rootsToProcess - testRootsToProcess 36 fun Collection<AggregatedRootIr>.rootsToString() = map { it.root }.joinToString() 37 if (appRootsToProcess.size > 1) { 38 throw InvalidRootsException( 39 "Cannot process multiple app roots in the same compilation unit: " + 40 appRootsToProcess.rootsToString() 41 ) 42 } 43 if (testRootsToProcess.isNotEmpty() && appRootsToProcess.isNotEmpty()) { 44 throw InvalidRootsException(""" 45 Cannot process test roots and app roots in the same compilation unit: 46 App root in this compilation unit: ${appRootsToProcess.rootsToString()} 47 Test roots in this compilation unit: ${testRootsToProcess.rootsToString()} 48 """.trimIndent() 49 ) 50 } 51 // Perform validation across roots previous compilation units. 52 if (!isCrossCompilationRootValidationDisabled) { 53 val alreadyProcessedTestRoots = aggregatedRoots.filter { 54 it.isTestRoot && processedRootNames.contains(it.root) 55 } 56 // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this. 57 if (alreadyProcessedTestRoots.isNotEmpty() && rootsToProcess.isNotEmpty()) { 58 throw InvalidRootsException(""" 59 Cannot process new roots when there are test roots from a previous compilation unit: 60 Test roots from previous compilation unit: ${alreadyProcessedTestRoots.rootsToString()} 61 All roots from this compilation unit: ${rootsToProcess.rootsToString()} 62 """.trimIndent() 63 ) 64 } 65 val alreadyProcessedAppRoots = aggregatedRoots.filter { 66 !it.isTestRoot && processedRootNames.contains(it.root) 67 } 68 if (alreadyProcessedAppRoots.isNotEmpty() && appRootsToProcess.isNotEmpty()) { 69 throw InvalidRootsException(""" 70 Cannot process new app roots when there are app roots from a previous compilation unit: 71 App roots in previous compilation unit: ${alreadyProcessedAppRoots.rootsToString()} 72 App roots in this compilation unit: ${appRootsToProcess.rootsToString()} 73 """.trimIndent() 74 ) 75 } 76 } 77 return rootsToProcess.toSet() 78 } 79 } 80 81 // An exception thrown when root validation fails. 82 class InvalidRootsException(msg: String) : Exception(msg) 83