]> git.lizzy.rs Git - rust.git/blob - src/etc/check_missing_items.py
Sync rust-lang/portable-simd@5f49d4c8435a25d804b2f375e949cb25479f5be9
[rust.git] / src / etc / check_missing_items.py
1 #!/usr/bin/env python
2
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.
6
7 # FIXME: Better error output
8
9 import sys
10 import json
11
12 crate = json.load(open(sys.argv[1], encoding="utf-8"))
13
14
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)
19     sys.exit(1)
20
21
22 # local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have
23 # to be in `paths`
24 def valid_id(item_id):
25     return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"]
26
27
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"])
45
46
47 def check_generic_param(param):
48     if "type" in param["kind"]:
49         ty = param["kind"]["type"]
50         if ty["default"]:
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"])
56
57
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"])
63
64
65 def check_decl(decl):
66     for (_name, ty) in decl["inputs"]:
67         check_type(ty)
68     if decl["output"]:
69         check_type(decl["output"])
70
71
72 def check_type(ty):
73     if ty["kind"] == "resolved_path":
74         for bound in ty["inner"]["param_names"]:
75             check_generic_bound(bound)
76         args = ty["inner"]["args"]
77         if args:
78             if "angle_bracketed" in args:
79                 for arg in args["angle_bracketed"]["args"]:
80                     if "type" in arg:
81                         check_type(arg["type"])
82                     elif "const" in arg:
83                         check_type(arg["const"]["type"])
84                 for binding in args["angle_bracketed"]["bindings"]:
85                     if "equality" in binding["binding"]:
86                         term = binding["binding"]["equality"]
87                         if "type" in term: check_type(term["type"])
88                         elif "const" in term: check_type(term["const"])
89                     elif "constraint" in binding["binding"]:
90                         for bound in binding["binding"]["constraint"]:
91                             check_generic_bound(bound)
92             elif "parenthesized" in args:
93                 for ty in args["parenthesized"]["inputs"]:
94                     check_type(ty)
95                 if args["parenthesized"]["output"]:
96                     check_type(args["parenthesized"]["output"])
97         if not valid_id(ty["inner"]["id"]):
98             print("Type contained an invalid ID:", ty["inner"]["id"])
99             sys.exit(1)
100     elif ty["kind"] == "tuple":
101         for ty in ty["inner"]:
102             check_type(ty)
103     elif ty["kind"] == "slice":
104         check_type(ty["inner"])
105     elif ty["kind"] == "impl_trait":
106         for bound in ty["inner"]:
107             check_generic_bound(bound)
108     elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"):
109         check_type(ty["inner"]["type"])
110     elif ty["kind"] == "function_pointer":
111         for param in ty["inner"]["generic_params"]:
112             check_generic_param(param)
113         check_decl(ty["inner"]["decl"])
114     elif ty["kind"] == "qualified_path":
115         check_type(ty["inner"]["self_type"])
116         check_type(ty["inner"]["trait"])
117
118
119 work_list = set([crate["root"]])
120 visited = work_list.copy()
121
122 while work_list:
123     current = work_list.pop()
124     visited.add(current)
125     item = get_local_item(current)
126     # check intradoc links
127     for (_name, link) in item["links"].items():
128         if not valid_id(link):
129             print("Intra-doc link contains invalid ID:", link)
130
131     # check all fields that reference types such as generics as well as nested items
132     # (modules, structs, traits, and enums)
133     if item["kind"] == "module":
134         work_list |= set(item["inner"]["items"]) - visited
135     elif item["kind"] == "struct":
136         check_generics(item["inner"]["generics"])
137         work_list |= (
138             set(item["inner"]["fields"]) | set(item["inner"]["impls"])
139         ) - visited
140     elif item["kind"] == "struct_field":
141         check_type(item["inner"])
142     elif item["kind"] == "enum":
143         check_generics(item["inner"]["generics"])
144         work_list |= (
145             set(item["inner"]["variants"]) | set(item["inner"]["impls"])
146         ) - visited
147     elif item["kind"] == "variant":
148         if item["inner"]["variant_kind"] == "tuple":
149             for ty in item["inner"]["variant_inner"]:
150                 check_type(ty)
151         elif item["inner"]["variant_kind"] == "struct":
152             work_list |= set(item["inner"]["variant_inner"]) - visited
153     elif item["kind"] in ("function", "method"):
154         check_generics(item["inner"]["generics"])
155         check_decl(item["inner"]["decl"])
156     elif item["kind"] in ("static", "constant", "assoc_const"):
157         check_type(item["inner"]["type"])
158     elif item["kind"] == "typedef":
159         check_type(item["inner"]["type"])
160         check_generics(item["inner"]["generics"])
161     elif item["kind"] == "opaque_ty":
162         check_generics(item["inner"]["generics"])
163         for bound in item["inner"]["bounds"]:
164             check_generic_bound(bound)
165     elif item["kind"] == "trait_alias":
166         check_generics(item["inner"]["params"])
167         for bound in item["inner"]["bounds"]:
168             check_generic_bound(bound)
169     elif item["kind"] == "trait":
170         check_generics(item["inner"]["generics"])
171         for bound in item["inner"]["bounds"]:
172             check_generic_bound(bound)
173         work_list |= (
174             set(item["inner"]["items"]) | set(item["inner"]["implementors"])
175         ) - visited
176     elif item["kind"] == "impl":
177         check_generics(item["inner"]["generics"])
178         if item["inner"]["trait"]:
179             check_type(item["inner"]["trait"])
180         if item["inner"]["blanket_impl"]:
181             check_type(item["inner"]["blanket_impl"])
182         check_type(item["inner"]["for"])
183         for assoc_item in item["inner"]["items"]:
184             if not valid_id(assoc_item):
185                 print("Impl block referenced a missing ID:", assoc_item)
186                 sys.exit(1)
187     elif item["kind"] == "assoc_type":
188         for bound in item["inner"]["bounds"]:
189             check_generic_bound(bound)
190         if item["inner"]["default"]:
191             check_type(item["inner"]["default"])