1 /* 2 * Copyright (C) 2024 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 com.android.tools.metalava.model 18 19 import com.android.tools.metalava.model.snapshot.CodebaseSnapshotTaker 20 import com.android.tools.metalava.model.snapshot.EmittableDelegatingVisitor 21 22 /** 23 * Encapsulates [codebase] to visit and a [visitorFactory] that if given a [DelegatedVisitor] will 24 * return an [ItemVisitor] that can be used to visit some fragment of the [codebase]. 25 */ 26 abstract class CodebaseFragment private constructor() { 27 28 /** The [Codebase] whose fragment will be visited. */ 29 abstract val codebase: Codebase 30 31 /** 32 * A factory for creating an [ItemVisitor] that delegates to a [DelegatedVisitor]. 33 * 34 * The [ItemVisitor] is used to determine which parts of [codebase] are considered to be defined 35 * within and emitted from this fragment. 36 */ 37 protected abstract val visitorFactory: (DelegatedVisitor) -> ItemVisitor 38 39 /** 40 * Create an [ItemVisitor] that will visit this fragment and delegate its contents to 41 * [delegate]. 42 */ createVisitornull43 fun createVisitor(delegate: DelegatedVisitor) = visitorFactory(delegate) 44 45 /** 46 * Return a [CodebaseFragment] that will take a snapshot of this [CodebaseFragment]. 47 * 48 * @param referenceVisitorFactory a factory for creating an [ItemVisitor] that delegates to a 49 * [DelegatedVisitor]. The [ItemVisitor] is used to determine which parts of [codebase] will 50 * be referenced from within but not emitted from the snapshot. 51 */ 52 fun snapshotIncludingRevertedItems( 53 referenceVisitorFactory: (DelegatedVisitor) -> ItemVisitor, 54 ): CodebaseFragment { 55 return LazyCodebaseFragment( 56 { 57 CodebaseSnapshotTaker.takeSnapshot( 58 codebase, 59 definitionVisitorFactory = visitorFactory, 60 referenceVisitorFactory = referenceVisitorFactory, 61 ) 62 }, 63 ::EmittableDelegatingVisitor, 64 ) 65 } 66 67 /** Visit this fragment, delegating to [delegate]. */ acceptnull68 fun accept(delegate: DelegatedVisitor) { 69 val visitor = visitorFactory(delegate) 70 codebase.accept(visitor) 71 } 72 73 companion object { 74 /** 75 * Create a [CodebaseFragment] from an existing [Codebase]. 76 * 77 * @param factory a factory for creating an [ItemVisitor] that delegates to a 78 * [DelegatedVisitor]. The [ItemVisitor] is used to determine which parts of [codebase] 79 * are considered to be defined within and emitted from this fragment. 80 */ createnull81 fun create( 82 codebase: Codebase, 83 factory: (DelegatedVisitor) -> ItemVisitor, 84 ): CodebaseFragment = ExistingCodebaseFragment(codebase, factory) 85 } 86 87 /** A [CodebaseFragment] of an existing [Codebase]. */ 88 private class ExistingCodebaseFragment( 89 override val codebase: Codebase, 90 override val visitorFactory: (DelegatedVisitor) -> ItemVisitor, 91 ) : CodebaseFragment() 92 93 /** A [CodebaseFragment] of a [Codebase] that will be provided lazily. */ 94 private class LazyCodebaseFragment( 95 codebaseProvider: () -> Codebase, 96 override val visitorFactory: (DelegatedVisitor) -> ItemVisitor, 97 ) : CodebaseFragment() { 98 99 override val codebase by lazy(LazyThreadSafetyMode.NONE) { codebaseProvider() } 100 } 101 } 102