@@ -55,6 +55,30 @@ def generic_type_name(v):
55
55
return type (v ).__name__
56
56
57
57
58
+ def record_custom_annotation_imports (annotation , namespace ):
59
+ """
60
+ Records imports for custom annotations in the given namespace.
61
+
62
+ """
63
+ # first, check the annotation *type*
64
+ if annotation .annotation_type .namespace .name != namespace .name :
65
+ namespace .add_imported_namespace (
66
+ annotation .annotation_type .namespace ,
67
+ imported_annotation_type = True )
68
+
69
+ # second, check if we need to import the annotation itself
70
+
71
+ # the annotation namespace is currently not actually used in the
72
+ # backends, which reconstruct the annotation from the annotation
73
+ # type directly. This could be changed in the future, and at
74
+ # the IR level it makes sense to include the dependency
75
+
76
+ if annotation .namespace .name != namespace .name :
77
+ namespace .add_imported_namespace (
78
+ annotation .namespace ,
79
+ imported_annotation = True )
80
+
81
+
58
82
class DataType (object ):
59
83
"""
60
84
Abstract class representing a data type.
@@ -118,6 +142,12 @@ class Composite(DataType): # pylint: disable=abstract-method
118
142
Composite types are any data type which can be constructed using primitive
119
143
data types and other composite types.
120
144
"""
145
+ def __init__ (self ):
146
+ super (Composite , self ).__init__ ()
147
+ # contains custom annotations that apply to any containing data types (recursively)
148
+ # format is (location, CustomAnnotation) to indicate a custom annotation is applied
149
+ # to a location (Field or Alias)
150
+ self .recursive_custom_annotations = None
121
151
122
152
123
153
class Nullable (Composite ):
@@ -781,22 +811,7 @@ def set_attributes(self, doc, fields, parent_type=None):
781
811
# they are treated as globals at the IR level
782
812
for field in self .fields :
783
813
for annotation in field .custom_annotations :
784
- # first, check the annotation *type*
785
- if annotation .annotation_type .namespace .name != self .namespace .name :
786
- self .namespace .add_imported_namespace (
787
- annotation .annotation_type .namespace ,
788
- imported_annotation_type = True )
789
-
790
- # second, check if we need to import the annotation itself
791
-
792
- # the annotation namespace is currently not actually used in the
793
- # backends, which reconstruct the annotation from the annotation
794
- # type directly. This could be changed in the future, and at
795
- # the IR level it makes sense to include the dependency
796
- if annotation .namespace .name != self .namespace .name :
797
- self .namespace .add_imported_namespace (
798
- annotation .namespace ,
799
- imported_annotation = True )
814
+ record_custom_annotation_imports (annotation , self .namespace )
800
815
801
816
# Indicate that the attributes of the type have been populated.
802
817
self ._is_forward_ref = False
@@ -901,7 +916,6 @@ class Struct(UserDefined):
901
916
"""
902
917
Defines a product type: Composed of other primitive and/or struct types.
903
918
"""
904
- # pylint: disable=attribute-defined-outside-init
905
919
906
920
composite_type = 'struct'
907
921
@@ -1359,7 +1373,6 @@ def __repr__(self):
1359
1373
1360
1374
class Union (UserDefined ):
1361
1375
"""Defines a tagged union. Fields are variants."""
1362
- # pylint: disable=attribute-defined-outside-init
1363
1376
1364
1377
composite_type = 'union'
1365
1378
@@ -1830,25 +1843,7 @@ def set_annotations(self, annotations):
1830
1843
elif isinstance (annotation , CustomAnnotation ):
1831
1844
# Note: we don't need to do this for builtin annotations because
1832
1845
# they are treated as globals at the IR level
1833
-
1834
- # first, check the annotation *type*
1835
- if annotation .annotation_type .namespace .name != self .namespace .name :
1836
- self .namespace .add_imported_namespace (
1837
- annotation .annotation_type .namespace ,
1838
- imported_annotation_type = True )
1839
-
1840
- # second, check if we need to import the annotation itself
1841
-
1842
- # the annotation namespace is currently not actually used in the
1843
- # backends, which reconstruct the annotation from the annotation
1844
- # type directly. This could be changed in the future, and at
1845
- # the IR level it makes sense to include the dependency
1846
-
1847
- if annotation .namespace .name != self .namespace .name :
1848
- self .namespace .add_imported_namespace (
1849
- annotation .namespace ,
1850
- imported_annotation = True )
1851
-
1846
+ record_custom_annotation_imports (annotation , self .namespace )
1852
1847
self .custom_annotations .append (annotation )
1853
1848
else :
1854
1849
raise InvalidSpec ("Aliases only support 'Redacted' and custom annotations, not %r" %
@@ -2002,53 +1997,6 @@ def unwrap(data_type):
2002
1997
data_type = data_type .data_type
2003
1998
return data_type , unwrapped_nullable , unwrapped_alias
2004
1999
2005
- def get_custom_annotations_for_alias (data_type ):
2006
- """
2007
- Given a Stone data type, returns all custom annotations applied to it.
2008
- """
2009
- # annotations can only be applied to Aliases, but they can be wrapped in
2010
- # Nullable. also, Aliases pointing to other Aliases don't automatically
2011
- # inherit their custom annotations, so we might have to traverse.
2012
- result = []
2013
- data_type , _ = unwrap_nullable (data_type )
2014
- while is_alias (data_type ):
2015
- result .extend (data_type .custom_annotations )
2016
- data_type , _ = unwrap_nullable (data_type .data_type )
2017
- return result
2018
-
2019
- def get_custom_annotations_recursive (data_type ):
2020
- """
2021
- Given a Stone data type, returns all custom annotations applied to any of
2022
- its memebers, as well as submembers, ..., to an arbitrary depth.
2023
- """
2024
- # because Stone structs can contain references to themselves (or otherwise
2025
- # be cyclical), we need ot keep track of the data types we've already seen
2026
- data_types_seen = set ()
2027
-
2028
- def recurse (data_type ):
2029
- if data_type in data_types_seen :
2030
- return
2031
- data_types_seen .add (data_type )
2032
-
2033
- dt , _ , _ = unwrap (data_type )
2034
- if is_struct_type (dt ) or is_union_type (dt ):
2035
- for field in dt .fields :
2036
- for annotation in recurse (field .data_type ):
2037
- yield annotation
2038
- for annotation in field .custom_annotations :
2039
- yield annotation
2040
- elif is_list_type (dt ):
2041
- for annotation in recurse (dt .data_type ):
2042
- yield annotation
2043
- elif is_map_type (dt ):
2044
- for annotation in recurse (dt .value_data_type ):
2045
- yield annotation
2046
-
2047
- for annotation in get_custom_annotations_for_alias (data_type ):
2048
- yield annotation
2049
-
2050
- return recurse (data_type )
2051
-
2052
2000
2053
2001
def is_alias (data_type ):
2054
2002
return isinstance (data_type , Alias )
0 commit comments