3 # This test ensures that every ID in the produced json actually resolves to an item either in
4 # `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in
5 # any way correct, for example an empty map would pass.
7 # FIXME: Better error output
12 crate = json.load(open(sys.argv[1]))
15 def get_local_item(item_id):
16 if item_id in crate["index"]:
17 return crate["index"][item_id]
18 print("Missing local ID:", item_id)
22 # local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have
24 def valid_id(item_id):
25 return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"]
28 def check_generics(generics):
29 for param in generics["params"]:
30 check_generic_param(param)
31 for where_predicate in generics["where_predicates"]:
32 if "bound_predicate" in where_predicate:
33 pred = where_predicate["bound_predicate"]
34 check_type(pred["ty"])
35 for bound in pred["bounds"]:
36 check_generic_bound(bound)
37 elif "region_predicate" in where_predicate:
38 pred = where_predicate["region_predicate"]
39 for bound in pred["bounds"]:
40 check_generic_bound(bound)
41 elif "eq_predicate" in where_predicate:
42 pred = where_predicate["eq_predicate"]
43 check_type(pred["rhs"])
44 check_type(pred["lhs"])
47 def check_generic_param(param):
48 if "type" in param["kind"]:
49 ty = param["kind"]["type"]
51 check_type(ty["default"])
52 for bound in ty["bounds"]:
53 check_generic_bound(bound)
54 elif "const" in param["kind"]:
55 check_type(param["kind"]["const"])
58 def check_generic_bound(bound):
59 if "trait_bound" in bound:
60 for param in bound["trait_bound"]["generic_params"]:
61 check_generic_param(param)
62 check_type(bound["trait_bound"]["trait"])
66 for (_name, ty) in decl["inputs"]:
69 check_type(decl["output"])
73 if ty["kind"] == "resolved_path":
74 for bound in ty["inner"]["param_names"]:
75 check_generic_bound(bound)
76 args = ty["inner"]["args"]
78 if "angle_bracketed" in args:
79 for arg in args["angle_bracketed"]["args"]:
81 check_type(arg["type"])
83 check_type(arg["const"]["type"])
84 for binding in args["angle_bracketed"]["bindings"]:
85 if "equality" in binding["binding"]:
86 check_type(binding["binding"]["equality"])
87 elif "constraint" in binding["binding"]:
88 for bound in binding["binding"]["constraint"]:
89 check_generic_bound(bound)
90 elif "parenthesized" in args:
91 for ty in args["parenthesized"]["inputs"]:
93 if args["parenthesized"]["output"]:
94 check_type(args["parenthesized"]["output"])
95 if not valid_id(ty["inner"]["id"]):
96 print("Type contained an invalid ID:", ty["inner"]["id"])
98 elif ty["kind"] == "tuple":
99 for ty in ty["inner"]:
101 elif ty["kind"] == "slice":
102 check_type(ty["inner"])
103 elif ty["kind"] == "impl_trait":
104 for bound in ty["inner"]:
105 check_generic_bound(bound)
106 elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"):
107 check_type(ty["inner"]["type"])
108 elif ty["kind"] == "function_pointer":
109 for param in ty["inner"]["generic_params"]:
110 check_generic_param(param)
111 check_decl(ty["inner"]["decl"])
112 elif ty["kind"] == "qualified_path":
113 check_type(ty["inner"]["self_type"])
114 check_type(ty["inner"]["trait"])
117 work_list = set([crate["root"]])
118 visited = work_list.copy()
121 current = work_list.pop()
123 item = get_local_item(current)
124 # check intradoc links
125 for (_name, link) in item["links"].items():
126 if not valid_id(link):
127 print("Intra-doc link contains invalid ID:", link)
129 # check all fields that reference types such as generics as well as nested items
130 # (modules, structs, traits, and enums)
131 if item["kind"] == "module":
132 work_list |= set(item["inner"]["items"]) - visited
133 elif item["kind"] == "struct":
134 check_generics(item["inner"]["generics"])
136 set(item["inner"]["fields"]) | set(item["inner"]["impls"])
138 elif item["kind"] == "struct_field":
139 check_type(item["inner"])
140 elif item["kind"] == "enum":
141 check_generics(item["inner"]["generics"])
143 set(item["inner"]["variants"]) | set(item["inner"]["impls"])
145 elif item["kind"] == "variant":
146 if item["inner"]["variant_kind"] == "tuple":
147 for ty in item["inner"]["variant_inner"]:
149 elif item["inner"]["variant_kind"] == "struct":
150 work_list |= set(item["inner"]["variant_inner"]) - visited
151 elif item["kind"] in ("function", "method"):
152 check_generics(item["inner"]["generics"])
153 check_decl(item["inner"]["decl"])
154 elif item["kind"] in ("static", "constant", "assoc_const"):
155 check_type(item["inner"]["type"])
156 elif item["kind"] == "typedef":
157 check_type(item["inner"]["type"])
158 check_generics(item["inner"]["generics"])
159 elif item["kind"] == "opaque_ty":
160 check_generics(item["inner"]["generics"])
161 for bound in item["inner"]["bounds"]:
162 check_generic_bound(bound)
163 elif item["kind"] == "trait_alias":
164 check_generics(item["inner"]["params"])
165 for bound in item["inner"]["bounds"]:
166 check_generic_bound(bound)
167 elif item["kind"] == "trait":
168 check_generics(item["inner"]["generics"])
169 for bound in item["inner"]["bounds"]:
170 check_generic_bound(bound)
172 set(item["inner"]["items"]) | set(item["inner"]["implementors"])
174 elif item["kind"] == "impl":
175 check_generics(item["inner"]["generics"])
176 if item["inner"]["trait"]:
177 check_type(item["inner"]["trait"])
178 if item["inner"]["blanket_impl"]:
179 check_type(item["inner"]["blanket_impl"])
180 check_type(item["inner"]["for"])
181 for assoc_item in item["inner"]["items"]:
182 if not valid_id(assoc_item):
183 print("Impl block referenced a missing ID:", assoc_item)
185 elif item["kind"] == "assoc_type":
186 for bound in item["inner"]["bounds"]:
187 check_generic_bound(bound)
188 if item["inner"]["default"]:
189 check_type(item["inner"]["default"])