1*333d2b36SAndroid Build Coastguard Worker#!/usr/bin/env python 2*333d2b36SAndroid Build Coastguard Worker# 3*333d2b36SAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project 4*333d2b36SAndroid Build Coastguard Worker# 5*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*333d2b36SAndroid Build Coastguard Worker# 9*333d2b36SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*333d2b36SAndroid Build Coastguard Worker# 11*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*333d2b36SAndroid Build Coastguard Worker# limitations under the License. 16*333d2b36SAndroid Build Coastguard Worker"""Verify that one set of hidden API flags is a subset of another.""" 17*333d2b36SAndroid Build Coastguard Workerimport dataclasses 18*333d2b36SAndroid Build Coastguard Workerimport typing 19*333d2b36SAndroid Build Coastguard Worker 20*333d2b36SAndroid Build Coastguard Workerfrom itertools import chain 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker@dataclasses.dataclass() 24*333d2b36SAndroid Build Coastguard Workerclass Node: 25*333d2b36SAndroid Build Coastguard Worker """A node in the signature trie.""" 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Worker # The type of the node. 28*333d2b36SAndroid Build Coastguard Worker # 29*333d2b36SAndroid Build Coastguard Worker # Leaf nodes are of type "member". 30*333d2b36SAndroid Build Coastguard Worker # Interior nodes can be either "package", or "class". 31*333d2b36SAndroid Build Coastguard Worker type: str 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Worker # The selector of the node. 34*333d2b36SAndroid Build Coastguard Worker # 35*333d2b36SAndroid Build Coastguard Worker # That is a string that can be used to select the node, e.g. in a pattern 36*333d2b36SAndroid Build Coastguard Worker # that is passed to InteriorNode.get_matching_rows(). 37*333d2b36SAndroid Build Coastguard Worker selector: str 38*333d2b36SAndroid Build Coastguard Worker 39*333d2b36SAndroid Build Coastguard Worker def values(self, selector): 40*333d2b36SAndroid Build Coastguard Worker """Get the values from a set of selected nodes. 41*333d2b36SAndroid Build Coastguard Worker 42*333d2b36SAndroid Build Coastguard Worker :param selector: a function that can be applied to a key in the nodes 43*333d2b36SAndroid Build Coastguard Worker attribute to determine whether to return its values. 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker :return: A list of iterables of all the values associated with 46*333d2b36SAndroid Build Coastguard Worker this node and its children. 47*333d2b36SAndroid Build Coastguard Worker """ 48*333d2b36SAndroid Build Coastguard Worker values = [] 49*333d2b36SAndroid Build Coastguard Worker self.append_values(values, selector) 50*333d2b36SAndroid Build Coastguard Worker return values 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Worker def append_values(self, values, selector): 53*333d2b36SAndroid Build Coastguard Worker """Append the values associated with this node and its children. 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker For each item (key, child) in nodes the child node's values are returned 56*333d2b36SAndroid Build Coastguard Worker if and only if the selector returns True when called on its key. A child 57*333d2b36SAndroid Build Coastguard Worker node's values are all the values associated with it and all its 58*333d2b36SAndroid Build Coastguard Worker descendant nodes. 59*333d2b36SAndroid Build Coastguard Worker 60*333d2b36SAndroid Build Coastguard Worker :param selector: a function that can be applied to a key in the nodes 61*333d2b36SAndroid Build Coastguard Worker attribute to determine whether to return its values. 62*333d2b36SAndroid Build Coastguard Worker :param values: a list of a iterables of values. 63*333d2b36SAndroid Build Coastguard Worker """ 64*333d2b36SAndroid Build Coastguard Worker raise NotImplementedError("Please Implement this method") 65*333d2b36SAndroid Build Coastguard Worker 66*333d2b36SAndroid Build Coastguard Worker def child_nodes(self): 67*333d2b36SAndroid Build Coastguard Worker """Get an iterable of the child nodes of this node.""" 68*333d2b36SAndroid Build Coastguard Worker raise NotImplementedError("Please Implement this method") 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Worker 71*333d2b36SAndroid Build Coastguard Worker# pylint: disable=line-too-long 72*333d2b36SAndroid Build Coastguard Worker@dataclasses.dataclass() 73*333d2b36SAndroid Build Coastguard Workerclass InteriorNode(Node): 74*333d2b36SAndroid Build Coastguard Worker """An interior node in a trie. 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Worker Each interior node has a dict that maps from an element of a signature to 77*333d2b36SAndroid Build Coastguard Worker either another interior node or a leaf. Each interior node represents either 78*333d2b36SAndroid Build Coastguard Worker a package, class or nested class. Class members are represented by a Leaf. 79*333d2b36SAndroid Build Coastguard Worker 80*333d2b36SAndroid Build Coastguard Worker Associating the set of flags [public-api] with the signature 81*333d2b36SAndroid Build Coastguard Worker "Ljava/lang/Object;->String()Ljava/lang/String;" will cause the following 82*333d2b36SAndroid Build Coastguard Worker nodes to be created: 83*333d2b36SAndroid Build Coastguard Worker Node() 84*333d2b36SAndroid Build Coastguard Worker ^- package:java -> Node() 85*333d2b36SAndroid Build Coastguard Worker ^- package:lang -> Node() 86*333d2b36SAndroid Build Coastguard Worker ^- class:Object -> Node() 87*333d2b36SAndroid Build Coastguard Worker ^- member:String()Ljava/lang/String; -> Leaf([public-api]) 88*333d2b36SAndroid Build Coastguard Worker 89*333d2b36SAndroid Build Coastguard Worker Associating the set of flags [blocked,core-platform-api] with the signature 90*333d2b36SAndroid Build Coastguard Worker "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;" 91*333d2b36SAndroid Build Coastguard Worker will cause the following nodes to be created: 92*333d2b36SAndroid Build Coastguard Worker Node() 93*333d2b36SAndroid Build Coastguard Worker ^- package:java -> Node() 94*333d2b36SAndroid Build Coastguard Worker ^- package:lang -> Node() 95*333d2b36SAndroid Build Coastguard Worker ^- class:Character -> Node() 96*333d2b36SAndroid Build Coastguard Worker ^- class:UnicodeScript -> Node() 97*333d2b36SAndroid Build Coastguard Worker ^- member:of(I)Ljava/lang/Character$UnicodeScript; 98*333d2b36SAndroid Build Coastguard Worker -> Leaf([blocked,core-platform-api]) 99*333d2b36SAndroid Build Coastguard Worker """ 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Worker # pylint: enable=line-too-long 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Worker # A dict from an element of the signature to the Node/Leaf containing the 104*333d2b36SAndroid Build Coastguard Worker # next element/value. 105*333d2b36SAndroid Build Coastguard Worker nodes: typing.Dict[str, Node] = dataclasses.field(default_factory=dict) 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Worker # pylint: disable=line-too-long 108*333d2b36SAndroid Build Coastguard Worker @staticmethod 109*333d2b36SAndroid Build Coastguard Worker def signature_to_elements(signature): 110*333d2b36SAndroid Build Coastguard Worker """Split a signature or a prefix into a number of elements: 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Worker 1. The packages (excluding the leading L preceding the first package). 113*333d2b36SAndroid Build Coastguard Worker 2. The class names, from outermost to innermost. 114*333d2b36SAndroid Build Coastguard Worker 3. The member signature. 115*333d2b36SAndroid Build Coastguard Worker e.g. 116*333d2b36SAndroid Build Coastguard Worker Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript; 117*333d2b36SAndroid Build Coastguard Worker will be broken down into these elements: 118*333d2b36SAndroid Build Coastguard Worker 1. package:java 119*333d2b36SAndroid Build Coastguard Worker 2. package:lang 120*333d2b36SAndroid Build Coastguard Worker 3. class:Character 121*333d2b36SAndroid Build Coastguard Worker 4. class:UnicodeScript 122*333d2b36SAndroid Build Coastguard Worker 5. member:of(I)Ljava/lang/Character$UnicodeScript; 123*333d2b36SAndroid Build Coastguard Worker """ 124*333d2b36SAndroid Build Coastguard Worker # Remove the leading L. 125*333d2b36SAndroid Build Coastguard Worker # - java/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript; 126*333d2b36SAndroid Build Coastguard Worker text = signature.removeprefix("L") 127*333d2b36SAndroid Build Coastguard Worker # Split the signature between qualified class name and the class member 128*333d2b36SAndroid Build Coastguard Worker # signature. 129*333d2b36SAndroid Build Coastguard Worker # 0 - java/lang/Character$UnicodeScript 130*333d2b36SAndroid Build Coastguard Worker # 1 - of(I)Ljava/lang/Character$UnicodeScript; 131*333d2b36SAndroid Build Coastguard Worker parts = text.split(";->") 132*333d2b36SAndroid Build Coastguard Worker # If there is no member then this will be an empty list. 133*333d2b36SAndroid Build Coastguard Worker member = parts[1:] 134*333d2b36SAndroid Build Coastguard Worker # Split the qualified class name into packages, and class name. 135*333d2b36SAndroid Build Coastguard Worker # 0 - java 136*333d2b36SAndroid Build Coastguard Worker # 1 - lang 137*333d2b36SAndroid Build Coastguard Worker # 2 - Character$UnicodeScript 138*333d2b36SAndroid Build Coastguard Worker elements = parts[0].split("/") 139*333d2b36SAndroid Build Coastguard Worker last_element = elements[-1] 140*333d2b36SAndroid Build Coastguard Worker wildcard = [] 141*333d2b36SAndroid Build Coastguard Worker classes = [] 142*333d2b36SAndroid Build Coastguard Worker if "*" in last_element: 143*333d2b36SAndroid Build Coastguard Worker if last_element not in ("*", "**"): 144*333d2b36SAndroid Build Coastguard Worker raise Exception(f"Invalid signature '{signature}': invalid " 145*333d2b36SAndroid Build Coastguard Worker f"wildcard '{last_element}'") 146*333d2b36SAndroid Build Coastguard Worker packages = elements[0:-1] 147*333d2b36SAndroid Build Coastguard Worker # Cannot specify a wildcard and target a specific member 148*333d2b36SAndroid Build Coastguard Worker if member: 149*333d2b36SAndroid Build Coastguard Worker raise Exception(f"Invalid signature '{signature}': contains " 150*333d2b36SAndroid Build Coastguard Worker f"wildcard '{last_element}' and " 151*333d2b36SAndroid Build Coastguard Worker f"member signature '{member[0]}'") 152*333d2b36SAndroid Build Coastguard Worker wildcard = [last_element] 153*333d2b36SAndroid Build Coastguard Worker else: 154*333d2b36SAndroid Build Coastguard Worker packages = elements[0:-1] 155*333d2b36SAndroid Build Coastguard Worker # Split the class name into outer / inner classes 156*333d2b36SAndroid Build Coastguard Worker # 0 - Character 157*333d2b36SAndroid Build Coastguard Worker # 1 - UnicodeScript 158*333d2b36SAndroid Build Coastguard Worker classes = last_element.removesuffix(";").split("$") 159*333d2b36SAndroid Build Coastguard Worker 160*333d2b36SAndroid Build Coastguard Worker # Assemble the parts into a single list, adding prefixes to identify 161*333d2b36SAndroid Build Coastguard Worker # the different parts. If a wildcard is provided then it looks something 162*333d2b36SAndroid Build Coastguard Worker # like this: 163*333d2b36SAndroid Build Coastguard Worker # 0 - package:java 164*333d2b36SAndroid Build Coastguard Worker # 1 - package:lang 165*333d2b36SAndroid Build Coastguard Worker # 2 - * 166*333d2b36SAndroid Build Coastguard Worker # 167*333d2b36SAndroid Build Coastguard Worker # Otherwise, it looks something like this: 168*333d2b36SAndroid Build Coastguard Worker # 0 - package:java 169*333d2b36SAndroid Build Coastguard Worker # 1 - package:lang 170*333d2b36SAndroid Build Coastguard Worker # 2 - class:Character 171*333d2b36SAndroid Build Coastguard Worker # 3 - class:UnicodeScript 172*333d2b36SAndroid Build Coastguard Worker # 4 - member:of(I)Ljava/lang/Character$UnicodeScript; 173*333d2b36SAndroid Build Coastguard Worker return list( 174*333d2b36SAndroid Build Coastguard Worker chain([("package", x) for x in packages], 175*333d2b36SAndroid Build Coastguard Worker [("class", x) for x in classes], 176*333d2b36SAndroid Build Coastguard Worker [("member", x) for x in member], 177*333d2b36SAndroid Build Coastguard Worker [("wildcard", x) for x in wildcard])) 178*333d2b36SAndroid Build Coastguard Worker 179*333d2b36SAndroid Build Coastguard Worker # pylint: enable=line-too-long 180*333d2b36SAndroid Build Coastguard Worker 181*333d2b36SAndroid Build Coastguard Worker @staticmethod 182*333d2b36SAndroid Build Coastguard Worker def split_element(element): 183*333d2b36SAndroid Build Coastguard Worker element_type, element_value = element 184*333d2b36SAndroid Build Coastguard Worker return element_type, element_value 185*333d2b36SAndroid Build Coastguard Worker 186*333d2b36SAndroid Build Coastguard Worker @staticmethod 187*333d2b36SAndroid Build Coastguard Worker def element_type(element): 188*333d2b36SAndroid Build Coastguard Worker element_type, _ = InteriorNode.split_element(element) 189*333d2b36SAndroid Build Coastguard Worker return element_type 190*333d2b36SAndroid Build Coastguard Worker 191*333d2b36SAndroid Build Coastguard Worker @staticmethod 192*333d2b36SAndroid Build Coastguard Worker def elements_to_selector(elements): 193*333d2b36SAndroid Build Coastguard Worker """Compute a selector for a set of elements. 194*333d2b36SAndroid Build Coastguard Worker 195*333d2b36SAndroid Build Coastguard Worker A selector uniquely identifies a specific Node in the trie. It is 196*333d2b36SAndroid Build Coastguard Worker essentially a prefix of a signature (without the leading L). 197*333d2b36SAndroid Build Coastguard Worker 198*333d2b36SAndroid Build Coastguard Worker e.g. a trie containing "Ljava/lang/Object;->String()Ljava/lang/String;" 199*333d2b36SAndroid Build Coastguard Worker would contain nodes with the following selectors: 200*333d2b36SAndroid Build Coastguard Worker * "java" 201*333d2b36SAndroid Build Coastguard Worker * "java/lang" 202*333d2b36SAndroid Build Coastguard Worker * "java/lang/Object" 203*333d2b36SAndroid Build Coastguard Worker * "java/lang/Object;->String()Ljava/lang/String;" 204*333d2b36SAndroid Build Coastguard Worker """ 205*333d2b36SAndroid Build Coastguard Worker signature = "" 206*333d2b36SAndroid Build Coastguard Worker preceding_type = "" 207*333d2b36SAndroid Build Coastguard Worker for element in elements: 208*333d2b36SAndroid Build Coastguard Worker element_type, element_value = InteriorNode.split_element(element) 209*333d2b36SAndroid Build Coastguard Worker separator = "" 210*333d2b36SAndroid Build Coastguard Worker if element_type == "package": 211*333d2b36SAndroid Build Coastguard Worker separator = "/" 212*333d2b36SAndroid Build Coastguard Worker elif element_type == "class": 213*333d2b36SAndroid Build Coastguard Worker if preceding_type == "class": 214*333d2b36SAndroid Build Coastguard Worker separator = "$" 215*333d2b36SAndroid Build Coastguard Worker else: 216*333d2b36SAndroid Build Coastguard Worker separator = "/" 217*333d2b36SAndroid Build Coastguard Worker elif element_type == "wildcard": 218*333d2b36SAndroid Build Coastguard Worker separator = "/" 219*333d2b36SAndroid Build Coastguard Worker elif element_type == "member": 220*333d2b36SAndroid Build Coastguard Worker separator += ";->" 221*333d2b36SAndroid Build Coastguard Worker 222*333d2b36SAndroid Build Coastguard Worker if signature: 223*333d2b36SAndroid Build Coastguard Worker signature += separator 224*333d2b36SAndroid Build Coastguard Worker 225*333d2b36SAndroid Build Coastguard Worker signature += element_value 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Worker preceding_type = element_type 228*333d2b36SAndroid Build Coastguard Worker 229*333d2b36SAndroid Build Coastguard Worker return signature 230*333d2b36SAndroid Build Coastguard Worker 231*333d2b36SAndroid Build Coastguard Worker def add(self, signature, value, only_if_matches=False): 232*333d2b36SAndroid Build Coastguard Worker """Associate the value with the specific signature. 233*333d2b36SAndroid Build Coastguard Worker 234*333d2b36SAndroid Build Coastguard Worker :param signature: the member signature 235*333d2b36SAndroid Build Coastguard Worker :param value: the value to associated with the signature 236*333d2b36SAndroid Build Coastguard Worker :param only_if_matches: True if the value is added only if the signature 237*333d2b36SAndroid Build Coastguard Worker matches at least one of the existing top level packages. 238*333d2b36SAndroid Build Coastguard Worker :return: n/a 239*333d2b36SAndroid Build Coastguard Worker """ 240*333d2b36SAndroid Build Coastguard Worker # Split the signature into elements. 241*333d2b36SAndroid Build Coastguard Worker elements = self.signature_to_elements(signature) 242*333d2b36SAndroid Build Coastguard Worker # Find the Node associated with the deepest class. 243*333d2b36SAndroid Build Coastguard Worker node = self 244*333d2b36SAndroid Build Coastguard Worker for index, element in enumerate(elements[:-1]): 245*333d2b36SAndroid Build Coastguard Worker if element in node.nodes: 246*333d2b36SAndroid Build Coastguard Worker node = node.nodes[element] 247*333d2b36SAndroid Build Coastguard Worker elif only_if_matches and index == 0: 248*333d2b36SAndroid Build Coastguard Worker return 249*333d2b36SAndroid Build Coastguard Worker else: 250*333d2b36SAndroid Build Coastguard Worker selector = self.elements_to_selector(elements[0:index + 1]) 251*333d2b36SAndroid Build Coastguard Worker next_node = InteriorNode( 252*333d2b36SAndroid Build Coastguard Worker type=InteriorNode.element_type(element), selector=selector) 253*333d2b36SAndroid Build Coastguard Worker node.nodes[element] = next_node 254*333d2b36SAndroid Build Coastguard Worker node = next_node 255*333d2b36SAndroid Build Coastguard Worker # Add a Leaf containing the value and associate it with the member 256*333d2b36SAndroid Build Coastguard Worker # signature within the class. 257*333d2b36SAndroid Build Coastguard Worker last_element = elements[-1] 258*333d2b36SAndroid Build Coastguard Worker last_element_type = self.element_type(last_element) 259*333d2b36SAndroid Build Coastguard Worker if last_element_type != "member": 260*333d2b36SAndroid Build Coastguard Worker raise Exception( 261*333d2b36SAndroid Build Coastguard Worker f"Invalid signature: {signature}, does not identify a " 262*333d2b36SAndroid Build Coastguard Worker "specific member") 263*333d2b36SAndroid Build Coastguard Worker if last_element in node.nodes: 264*333d2b36SAndroid Build Coastguard Worker raise Exception(f"Duplicate signature: {signature}") 265*333d2b36SAndroid Build Coastguard Worker leaf = Leaf( 266*333d2b36SAndroid Build Coastguard Worker type=last_element_type, 267*333d2b36SAndroid Build Coastguard Worker selector=signature, 268*333d2b36SAndroid Build Coastguard Worker value=value, 269*333d2b36SAndroid Build Coastguard Worker ) 270*333d2b36SAndroid Build Coastguard Worker node.nodes[last_element] = leaf 271*333d2b36SAndroid Build Coastguard Worker 272*333d2b36SAndroid Build Coastguard Worker def get_matching_rows(self, pattern): 273*333d2b36SAndroid Build Coastguard Worker """Get the values (plural) associated with the pattern. 274*333d2b36SAndroid Build Coastguard Worker 275*333d2b36SAndroid Build Coastguard Worker e.g. If the pattern is a full signature then this will return a list 276*333d2b36SAndroid Build Coastguard Worker containing the value associated with that signature. 277*333d2b36SAndroid Build Coastguard Worker 278*333d2b36SAndroid Build Coastguard Worker If the pattern is a class then this will return a list containing the 279*333d2b36SAndroid Build Coastguard Worker values associated with all members of that class. 280*333d2b36SAndroid Build Coastguard Worker 281*333d2b36SAndroid Build Coastguard Worker If the pattern ends with "*" then the preceding part is treated as a 282*333d2b36SAndroid Build Coastguard Worker package and this will return a list containing the values associated 283*333d2b36SAndroid Build Coastguard Worker with all the members of all the classes in that package. 284*333d2b36SAndroid Build Coastguard Worker 285*333d2b36SAndroid Build Coastguard Worker If the pattern ends with "**" then the preceding part is treated 286*333d2b36SAndroid Build Coastguard Worker as a package and this will return a list containing the values 287*333d2b36SAndroid Build Coastguard Worker associated with all the members of all the classes in that package and 288*333d2b36SAndroid Build Coastguard Worker all sub-packages. 289*333d2b36SAndroid Build Coastguard Worker 290*333d2b36SAndroid Build Coastguard Worker :param pattern: the pattern which could be a complete signature or a 291*333d2b36SAndroid Build Coastguard Worker class, or package wildcard. 292*333d2b36SAndroid Build Coastguard Worker :return: an iterable containing all the values associated with the 293*333d2b36SAndroid Build Coastguard Worker pattern. 294*333d2b36SAndroid Build Coastguard Worker """ 295*333d2b36SAndroid Build Coastguard Worker elements = self.signature_to_elements(pattern) 296*333d2b36SAndroid Build Coastguard Worker node = self 297*333d2b36SAndroid Build Coastguard Worker 298*333d2b36SAndroid Build Coastguard Worker # Include all values from this node and all its children. 299*333d2b36SAndroid Build Coastguard Worker selector = lambda x: True 300*333d2b36SAndroid Build Coastguard Worker 301*333d2b36SAndroid Build Coastguard Worker last_element = elements[-1] 302*333d2b36SAndroid Build Coastguard Worker last_element_type, last_element_value = self.split_element(last_element) 303*333d2b36SAndroid Build Coastguard Worker if last_element_type == "wildcard": 304*333d2b36SAndroid Build Coastguard Worker elements = elements[:-1] 305*333d2b36SAndroid Build Coastguard Worker if last_element_value == "*": 306*333d2b36SAndroid Build Coastguard Worker # Do not include values from sub-packages. 307*333d2b36SAndroid Build Coastguard Worker selector = lambda x: InteriorNode.element_type(x) != "package" 308*333d2b36SAndroid Build Coastguard Worker 309*333d2b36SAndroid Build Coastguard Worker for element in elements: 310*333d2b36SAndroid Build Coastguard Worker if element in node.nodes: 311*333d2b36SAndroid Build Coastguard Worker node = node.nodes[element] 312*333d2b36SAndroid Build Coastguard Worker else: 313*333d2b36SAndroid Build Coastguard Worker return [] 314*333d2b36SAndroid Build Coastguard Worker 315*333d2b36SAndroid Build Coastguard Worker return node.values(selector) 316*333d2b36SAndroid Build Coastguard Worker 317*333d2b36SAndroid Build Coastguard Worker def append_values(self, values, selector): 318*333d2b36SAndroid Build Coastguard Worker for key, node in self.nodes.items(): 319*333d2b36SAndroid Build Coastguard Worker if selector(key): 320*333d2b36SAndroid Build Coastguard Worker node.append_values(values, lambda x: True) 321*333d2b36SAndroid Build Coastguard Worker 322*333d2b36SAndroid Build Coastguard Worker def child_nodes(self): 323*333d2b36SAndroid Build Coastguard Worker return self.nodes.values() 324*333d2b36SAndroid Build Coastguard Worker 325*333d2b36SAndroid Build Coastguard Worker 326*333d2b36SAndroid Build Coastguard Worker@dataclasses.dataclass() 327*333d2b36SAndroid Build Coastguard Workerclass Leaf(Node): 328*333d2b36SAndroid Build Coastguard Worker """A leaf of the trie""" 329*333d2b36SAndroid Build Coastguard Worker 330*333d2b36SAndroid Build Coastguard Worker # The value associated with this leaf. 331*333d2b36SAndroid Build Coastguard Worker value: typing.Any 332*333d2b36SAndroid Build Coastguard Worker 333*333d2b36SAndroid Build Coastguard Worker def append_values(self, values, selector): 334*333d2b36SAndroid Build Coastguard Worker values.append(self.value) 335*333d2b36SAndroid Build Coastguard Worker 336*333d2b36SAndroid Build Coastguard Worker def child_nodes(self): 337*333d2b36SAndroid Build Coastguard Worker return [] 338*333d2b36SAndroid Build Coastguard Worker 339*333d2b36SAndroid Build Coastguard Worker 340*333d2b36SAndroid Build Coastguard Workerdef signature_trie(): 341*333d2b36SAndroid Build Coastguard Worker return InteriorNode(type="root", selector="") 342