1 /* 2 * Copyright (C) 2023 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 /** 20 * An [ItemVisitor] that simply traverses an [Item] hierarchy calling [visitItem] for each [Item]. 21 * 22 * The [visitItem] method can affect the traversal through the [TraversalAction] value it returns. 23 * 24 * It intentionally does not visit [ParameterItem]s. 25 */ 26 abstract class TraversingVisitor : ItemVisitor { 27 28 enum class TraversalAction { 29 /** Continue normal traversal. */ 30 CONTINUE, 31 32 /** Skip the children of the current [Item] but continue with its sibling. */ 33 SKIP_CHILDREN, 34 35 /** Skip the whole traversal. */ 36 SKIP_TRAVERSAL, 37 } 38 39 private var traversalFinished = false 40 41 /** Visit the item returning an action for the [TraversingVisitor] to take. */ visitItemnull42 abstract fun visitItem(item: Item): TraversalAction 43 44 final override fun visit(cls: ClassItem) { 45 when (visitItem(cls)) { 46 TraversalAction.SKIP_TRAVERSAL -> { 47 traversalFinished = true 48 } 49 TraversalAction.SKIP_CHILDREN -> { 50 // Do nothing 51 } 52 TraversalAction.CONTINUE -> { 53 for (constructor in cls.constructors()) { 54 constructor.accept(this) 55 if (traversalFinished) return 56 } 57 58 for (method in cls.methods()) { 59 method.accept(this) 60 if (traversalFinished) return 61 } 62 63 for (property in cls.properties()) { 64 property.accept(this) 65 if (traversalFinished) return 66 } 67 68 for (field in cls.fields()) { 69 field.accept(this) 70 if (traversalFinished) return 71 } 72 73 for (innerCls in cls.innerClasses()) { 74 innerCls.accept(this) 75 if (traversalFinished) return 76 } 77 } 78 } 79 } 80 visitnull81 final override fun visit(field: FieldItem) { 82 val action = visitItem(field) 83 traversalFinished = action == TraversalAction.SKIP_TRAVERSAL 84 } 85 visitnull86 final override fun visit(method: MethodItem) { 87 val action = visitItem(method) 88 traversalFinished = action == TraversalAction.SKIP_TRAVERSAL 89 } 90 visitnull91 final override fun visit(pkg: PackageItem) { 92 when (visitItem(pkg)) { 93 TraversalAction.SKIP_TRAVERSAL -> { 94 traversalFinished = true 95 } 96 TraversalAction.SKIP_CHILDREN -> { 97 // Do nothing 98 } 99 TraversalAction.CONTINUE -> { 100 for (cls in pkg.topLevelClasses()) { 101 cls.accept(this) 102 if (traversalFinished) return 103 } 104 } 105 } 106 } 107 visitnull108 final override fun visit(packageList: PackageList) { 109 for (it in packageList.packages) { 110 it.accept(this) 111 if (traversalFinished) return 112 } 113 } 114 visitnull115 final override fun visit(parameter: ParameterItem) { 116 error("parameters should not be visited") 117 } 118 visitnull119 final override fun visit(property: PropertyItem) { 120 val action = visitItem(property) 121 traversalFinished = action == TraversalAction.SKIP_TRAVERSAL 122 } 123 } 124