11#include <unordered_map>
13#include <nlohmann/json.hpp>
15#define DUMP_OBJECT(obj) printf("%s\n", (obj).dump(2).c_str())
24 static constexpr const char *loc_keys[] = {
25 "lineno",
"col_offset",
"end_lineno",
"end_col_offset"};
26 for (
const char *lk : loc_keys)
35 const nlohmann::json &a,
36 const nlohmann::json &b)
38 for (
auto it = a.begin(); it != a.end(); ++it)
43 !b.contains(it.key()) ||
47 for (
auto it = b.begin(); it != b.end(); ++it)
56 const nlohmann::json &a,
57 const nlohmann::json &b)
59 if (a.size() != b.size())
61 for (
size_t i = 0; i < a.size(); ++i)
76 if (a.type() != b.type())
93 if (n.contains(
"_type") && n[
"_type"] ==
"Call")
95 for (
auto it = n.begin(); it != n.end(); ++it)
99 else if (n.is_array())
101 for (
const auto &e : n)
110 return stmt.value(
"_type",
"") ==
"Assign" && stmt[
"targets"].size() == 1 &&
111 stmt[
"targets"][0].value(
"_type",
"") ==
"Name" &&
112 stmt[
"value"].value(
"_type",
"") ==
"Name";
119 std::string result = module_name;
120 std::replace(result.begin(), result.end(),
'.',
'/');
124template <
typename JsonType>
127 if (!node.is_object())
132 node.contains(
"_type") && node[
"_type"] ==
"FunctionDef" &&
133 node.contains(
"name") && node[
"name"] == func_name)
139 for (
const auto &[
key,
value] : node.items())
141 if (
value.is_array())
143 for (
const auto &item :
value)
149 else if (
value.is_object())
158template <
typename JsonType>
159JsonType
find_class(
const JsonType &ast_json,
const std::string &class_name)
162 std::find_if(ast_json.begin(), ast_json.end(), [&](
const JsonType &obj) {
163 return obj.contains(
"_type") && obj[
"_type"] ==
"ClassDef" &&
164 obj[
"name"] == class_name;
167 return (it != ast_json.end()) ? *it : JsonType();
175 auto annotation_of = [&](
const Json &stmt,
bool on_self) -> Json {
176 if (stmt.value(
"_type",
"") !=
"AnnAssign" || !stmt.contains(
"target"))
178 const Json &target = stmt[
"target"];
181 ? target.value(
"_type",
"") ==
"Attribute" &&
182 target.value(
"attr",
"") == attr && target.contains(
"value") &&
183 target[
"value"].value(
"id",
"") ==
"self"
184 : target.value(
"_type",
"") ==
"Name" && target.value(
"id",
"") == attr;
185 return matches ? stmt[
"annotation"] : Json();
188 for (
const Json &member : class_node[
"body"])
190 Json annotation = annotation_of(member,
false);
191 if (!annotation.empty())
194 member.value(
"_type",
"") !=
"FunctionDef" ||
195 member[
"name"] !=
"__init__")
197 for (
const Json &stmt : member[
"body"])
199 annotation = annotation_of(stmt,
true);
200 if (!annotation.empty())
215 node.is_object() && node.value(
"_type",
"") ==
"Attribute" &&
216 node.value(
"attr",
"") == attr && node.contains(
"ctx") &&
217 node[
"ctx"].value(
"_type",
"") !=
"Load")
218 n += !non_self_only || node[
"value"].value(
"id",
"") !=
"self";
219 for (
const auto &child : node)
220 if (child.is_structured())
231 for (
const Json &member : class_node[
"body"])
234 member.value(
"_type",
"") !=
"FunctionDef" ||
235 member[
"name"] !=
"__init__")
237 for (
const Json &stmt : member[
"body"])
239 if (stmt.value(
"_type",
"") !=
"Assign" || stmt[
"targets"].size() != 1)
241 const Json &target = stmt[
"targets"][0];
242 const Json &
value = stmt[
"value"];
244 target.value(
"_type",
"") ==
"Attribute" &&
245 target.value(
"attr",
"") == attr &&
246 target[
"value"].value(
"id",
"") ==
"self" &&
247 value.value(
"_type",
"") ==
"Call" &&
248 value[
"func"].value(
"_type",
"") ==
"Name")
249 return value[
"func"][
"id"].template get<std::string>();
255template <
typename JsonType>
258 if (function_def.contains(
"decorator_list"))
259 for (
const auto &dec : function_def[
"decorator_list"])
261 dec.value(
"_type", std::string()) ==
"Name" &&
262 dec.value(
"id", std::string()) ==
"property")
269template <
typename JsonType>
272 for (
const auto &cls : ast_body)
273 if (cls.value(
"_type", std::string()) ==
"ClassDef" && cls.contains(
"body"))
274 for (
const auto &stmt : cls[
"body"])
276 stmt.value(
"_type", std::string()) ==
"FunctionDef" &&
283template <
typename JsonType>
287 node.is_object() && node.value(
"_type",
"") ==
"ClassDef" &&
288 node.contains(
"body"))
289 for (
const auto &stmt : node[
"body"])
291 stmt.value(
"_type",
"") ==
"FunctionDef" &&
292 stmt.value(
"name",
"") == name)
294 if (node.is_object() || node.is_array())
295 for (
const auto &child : node)
305template <
typename JsonType>
307 const JsonType &ast_body,
308 const std::string &class_name,
309 const std::string &method_name)
311 const JsonType cls =
find_class(ast_body, class_name);
312 if (cls.empty() || !cls.contains(
"body"))
315 for (
const auto &stmt : cls[
"body"])
318 stmt.value(
"_type", std::string()) !=
"FunctionDef" ||
319 stmt.value(
"name", std::string()) != method_name)
324 if (cls.contains(
"bases"))
325 for (
const auto &
base : cls[
"bases"])
327 base.contains(
"id") &&
329 ast_body,
base[
"id"].
template get<std::string>(), method_name))
337template <
typename JsonType>
339 const JsonType &ast_body,
340 const std::string &class_name,
341 const std::string &method_name)
343 const JsonType cls =
find_class(ast_body, class_name);
344 if (cls.empty() || !cls.contains(
"body"))
347 for (
const auto &stmt : cls[
"body"])
349 stmt.value(
"_type", std::string()) ==
"FunctionDef" &&
350 stmt.value(
"name", std::string()) == method_name)
353 if (cls.contains(
"bases"))
354 for (
const auto &
base : cls[
"bases"])
356 base.contains(
"id") &&
base[
"id"] != class_name &&
358 ast_body,
base[
"id"].
template get<std::string>(), method_name))
365template <
typename JsonType>
368 std::size_t
count = 0;
369 if (node.is_object() && node.value(
"_type",
"") ==
"ClassDef")
371 if (node.is_object() || node.is_array())
372 for (
const auto &child : node)
380template <
typename JsonType>
382 const JsonType &body,
383 const std::string &class_name,
384 bool in_function =
false)
387 for (
const auto &node : body)
389 if (!node.is_object() || !node.contains(
"_type"))
392 const auto &type = node[
"_type"];
393 if (in_function && type ==
"ClassDef" && node[
"name"] == class_name)
397 (type ==
"FunctionDef" || type ==
"AsyncFunctionDef") &&
398 node.contains(
"body"))
406template <
typename JsonType>
408 const JsonType &node,
409 const std::string &class_name,
410 std::vector<int> &lines)
414 for (
const auto &child : node)
419 if (!node.is_object())
422 const bool is_class_def = node.value(
"_type",
"") ==
"ClassDef";
423 if (is_class_def && node.value(
"name",
"") == class_name)
424 lines.push_back(node.value(
"lineno", 0));
426 for (
const auto &child : node.items())
429 if (is_class_def && child.key() ==
"body")
431 for (
const auto &stmt : child.value())
432 if (stmt.value(
"_type",
"") !=
"ClassDef")
440template <
typename JsonType>
441bool is_class(
const std::string &name,
const JsonType &ast_json)
444 if (
find_class(ast_json[
"body"], name) != JsonType())
456 static std::unordered_map<std::string, JsonType> module_cache;
461 if (!ast_json.contains(
"ast_output_dir"))
464 const std::string output_dir =
465 ast_json[
"ast_output_dir"].template get<std::string>();
470 auto load_and_check = [&](
const std::string &module_name) ->
bool {
471 const std::string
path =
473 auto it = module_cache.find(
path);
474 if (it == module_cache.end())
476 std::ifstream f(
path);
481 it = module_cache.emplace(
path, std::move(j)).first;
486 for (
const auto &obj : ast_json[
"body"])
488 if (obj[
"_type"] ==
"ImportFrom")
493 !obj[
"module"].is_null() &&
494 load_and_check(obj[
"module"].
template get<std::string>()))
497 else if (obj[
"_type"] ==
"Import")
499 for (
const auto &imported : obj[
"names"])
501 if (load_and_check(imported[
"name"].
template get<std::string>()))
510template <
typename JsonType>
511bool is_module(
const std::string &module_name,
const JsonType &ast)
513 static std::unordered_map<std::string, bool> is_module_cache;
515 if (!ast.contains(
"ast_output_dir"))
519 const std::string dir = ast[
"ast_output_dir"].template get<std::string>();
520 const std::string
path = dir +
"/" + rel;
522 auto it = is_module_cache.find(
path);
523 if (it != is_module_cache.end())
531 const std::filesystem::path
full(
path);
534 for (std::filesystem::directory_iterator dit(
full.parent_path(), ec), end;
538 if (dit->path().filename() ==
full.filename())
544 is_module_cache.emplace(
path, result);
549template <
typename JsonType>
552 for (
const auto &elem :
json)
554 if (elem[
"_type"] ==
"FunctionDef" && elem[
"name"] == func_name)
561template <
typename JsonType>
564 for (
auto &elem :
json)
566 if (elem[
"_type"] ==
"FunctionDef" && elem[
"name"] == func_name)
569 throw std::runtime_error(
"Function " + func_name +
" not found\n");
573template <
typename JsonType>
576 const std::string &
module,
577 const std::string &entity)
579 for (
const auto &stmt : ast[
"body"])
582 stmt.contains(
"_type") && stmt[
"_type"] ==
"ImportFrom" &&
583 stmt.contains(
"module") && stmt[
"module"] ==
module &&
584 stmt.contains(
"names"))
586 for (
const auto &name : stmt[
"names"])
587 if (name.contains(
"name") && name[
"name"] == entity)
594template <
typename JsonType>
598 for (
const auto &node : ast[
"body"])
600 if (node[
"_type"] ==
"ImportFrom" || node[
"_type"] ==
"Import")
602 for (
const auto &name : node[
"names"])
603 if (name[
"name"] == func_name)
607 throw std::runtime_error(
"Function " + func_name +
" not found\n");
613 if (!node.is_object())
616 const std::string type = node.value(
"_type",
"");
618 return node.value(
"id",
"");
620 if (type ==
"Attribute")
623 dotted_name(node.value(
"value", nlohmann::json::object()));
624 std::string right = node.value(
"attr",
"");
625 if (!left.empty() && !right.empty())
626 return left +
"." + right;
627 return right.empty() ? left : right;
639 for (
const auto &node : ast[
"body"])
641 const std::string type = node.value(
"_type",
"");
642 if (type !=
"Import" && type !=
"ImportFrom")
644 const std::string from = type ==
"ImportFrom" && node[
"module"].is_string()
645 ? node[
"module"].get<std::string>() +
"."
647 for (
const auto &alias : node[
"names"])
649 const std::string bound = alias[
"asname"].is_string()
650 ? alias[
"asname"].get<std::string>()
651 : alias[
"name"].get<std::string>();
652 if (name == bound || name.starts_with(bound +
"."))
653 return from + alias[
"name"].get<std::string>() +
654 name.substr(bound.size());
664 const std::string prefix =
"collections.abc.";
667 !resolved.starts_with(prefix) ||
668 resolved.find(
'.', prefix.size()) != std::string::npos)
670 return resolved.substr(prefix.size());
673template <
typename JsonType>
677 for (
auto &node : ast[
"body"])
679 if (node[
"_type"] ==
"ImportFrom" || node[
"_type"] ==
"Import")
681 for (
const auto &name : node[
"names"])
683 if (name[
"_type"] ==
"alias" && name[
"asname"] == obj_name)
689 std::size_t dot_pos = obj_name.rfind(
'.');
690 if (dot_pos == std::string::npos)
693 std::string prefix = obj_name.substr(0, dot_pos);
694 std::string suffix = obj_name.substr(dot_pos);
697 if (resolved_prefix != prefix)
698 return resolved_prefix + suffix;
703template <
typename JsonType>
704const JsonType
get_var_node(
const std::string &var_name,
const JsonType &block)
706 auto find_in_body = [&](
const JsonType &body,
const auto &self) -> JsonType {
707 for (
auto &element : body)
711 element[
"_type"] ==
"AnnAssign" && element.contains(
"target") &&
712 element[
"target"].contains(
"id") && element[
"target"][
"id"] == var_name)
717 element[
"_type"] ==
"Assign" && element.contains(
"targets") &&
718 !element[
"targets"].empty() &&
719 element[
"targets"][0].contains(
"_type") &&
720 element[
"targets"][0][
"_type"] ==
"Name" &&
721 element[
"targets"][0].contains(
"id") &&
722 element[
"targets"][0][
"id"] == var_name)
727 element.contains(
"_type") &&
728 (element[
"_type"] ==
"FunctionDef" || element[
"_type"] ==
"ClassDef" ||
729 element[
"_type"] ==
"Lambda"))
733 for (
const auto &
key : {
"body",
"orelse",
"finalbody"})
735 if (element.contains(
key) && element[
key].is_array())
737 JsonType nested = self(element[
key], self);
744 if (element.contains(
"handlers") && element[
"handlers"].is_array())
746 for (
auto &handler : element[
"handlers"])
748 if (handler.contains(
"body") && handler[
"body"].is_array())
750 JsonType nested = self(handler[
"body"], self);
758 if (element.contains(
"cases") && element[
"cases"].is_array())
760 for (
auto &case_node : element[
"cases"])
762 if (case_node.contains(
"body") && case_node[
"body"].is_array())
764 JsonType nested = self(case_node[
"body"], self);
774 if (block.contains(
"body") && block[
"body"].is_array())
776 JsonType found = find_in_body(block[
"body"], find_in_body);
781 if (block.contains(
"args"))
783 for (
auto &arg : block[
"args"][
"args"])
784 if (arg.contains(
"arg") && arg[
"arg"] == var_name)
794 std::vector<std::string>
path;
798 while (
pos != std::string::npos)
814template <
typename JsonType>
817 const size_t sep = name.find(
"@C@");
818 if (sep == std::string::npos)
820 const std::string class_name = name.substr(0, sep);
821 name.erase(0, sep + 3);
822 const JsonType *scope =
nullptr;
823 for (
const auto &elem : body)
824 if (elem[
"_type"] ==
"ClassDef" && elem[
"name"] == class_name)
825 scope = &elem[
"body"];
832template <
typename JsonType>
839 std::function<JsonType(
const JsonType &,
size_t)> search_recursive;
841 [&](
const JsonType &parent_body,
size_t depth) -> JsonType {
847 if (scope ==
nullptr)
850 for (
const auto &elem : *scope)
852 if (elem[
"_type"] ==
"FunctionDef" && elem[
"name"] == target_name)
859 if (elem.contains(
"body") && elem[
"body"].is_array())
860 return search_recursive(elem[
"body"],
depth + 1);
867 JsonType result = search_recursive(ast[
"body"], 0);
872 for (
const auto &elem : ast[
"body"])
874 if (elem[
"_type"] ==
"ClassDef" && elem.contains(
"body"))
876 result = search_recursive(elem[
"body"], 0);
886template <
typename JsonType>
890 if (func_node.empty())
894 if (func_node.contains(
"args") && func_node[
"args"].contains(
"args"))
896 for (
const auto &arg : func_node[
"args"][
"args"])
898 if (arg.contains(
"arg") && arg[
"arg"] == var_name)
904 if (func_node.contains(
"args") && func_node[
"args"].contains(
"kwonlyargs"))
906 for (
const auto &arg : func_node[
"args"][
"kwonlyargs"])
908 if (arg.contains(
"arg") && arg[
"arg"] == var_name)
917template <
typename JsonType>
919 const std::string &var_name,
932 for (
int scope_level =
static_cast<int>(function_path.size()) - 1;
937 std::vector<std::string> partial_path(
938 function_path.begin(), function_path.begin() + scope_level + 1);
943 if (!func_node.empty())
956template <
typename JsonType>
959 if (annotation.contains(
"id"))
960 return annotation[
"id"];
963 annotation.contains(
"_type") && annotation[
"_type"] ==
"Subscript" &&
964 annotation.contains(
"value") && annotation[
"value"].contains(
"id"))
967 annotation[
"value"][
"id"].template get<std::string>();
968 if (annotation.contains(
"slice") && annotation[
"slice"].contains(
"id"))
970 annotation[
"slice"][
"id"].template get<std::string>() +
"]";
974 if (annotation.contains(
"value") && annotation[
"value"].contains(
"id"))
975 return annotation[
"value"][
"id"];
984 std::vector<std::string> parts;
987 for (
size_t i = 0; i <= s.size(); ++i)
989 if (i == s.size() || (s[i] ==
',' &&
depth == 0))
991 std::string part = s.substr(start, i - start);
992 const size_t b = part.find_first_not_of(
" \t");
993 if (b != std::string::npos)
994 parts.push_back(part.substr(b, part.find_last_not_of(
" \t") - b + 1));
997 else if (s[i] ==
'[')
999 else if (s[i] ==
']')
1011template <
typename JsonType>
1014 if (!annotation.is_object())
1017 if (annotation.contains(
"id") && annotation[
"id"].is_string())
1018 return annotation[
"id"];
1020 if (annotation.value(
"_type",
"") !=
"Subscript")
1024 if (
base.empty() || !annotation.contains(
"slice"))
1027 const auto &slice = annotation[
"slice"];
1030 if (slice.value(
"_type",
"") ==
"Tuple" && slice.contains(
"elts"))
1033 for (
const auto &elt : slice[
"elts"])
1036 if (rendered.empty())
1038 if (!params.empty())
1042 return params.empty() ?
base :
base +
"[" + params +
"]";
1046 return param.empty() ?
"" :
base +
"[" + param +
"]";
1049template <
typename JsonType>
1051 const std::string &var_name,
1053 const JsonType &ast)
1056 while (!
value.empty() &&
value[
"_type"] !=
"arg" &&
1057 value[
"value"][
"_type"] ==
"Name")
1066 const nlohmann::json &node,
1067 const std::string &kind,
1068 const std::string &name)
1070 static const std::map<std::string, std::string> name_field = {
1072 {
"FunctionDef",
"name"},
1073 {
"AsyncFunctionDef",
"name"},
1074 {
"ClassDef",
"name"},
1075 {
"ExceptHandler",
"name"},
1076 {
"MatchAs",
"name"},
1077 {
"MatchStar",
"name"},
1078 {
"Global",
"names"},
1079 {
"Nonlocal",
"names"}};
1080 const auto it = name_field.find(kind);
1081 if (it == name_field.end() || !node.contains(it->second))
1083 const nlohmann::json &field = node[it->second];
1084 return field.is_array() ? std::count(field.begin(), field.end(), name)
1095 if (node.is_object())
1097 const std::string kind = node.value(
"_type",
"");
1099 n += node.value(
"id",
"") == name &&
1100 node[
"ctx"].value(
"_type",
"") !=
"Load";
1101 else if (kind ==
"alias")
1102 n += (node[
"asname"].is_null() ? node[
"name"] : node[
"asname"]) == name;
1106 for (
const auto &child : node)
1107 if (child.is_structured())
1113inline const nlohmann::json *
1116 auto binds = [&](
const nlohmann::json &target) {
1117 return target.value(
"_type",
"") ==
"Name" && target[
"id"] == name;
1119 for (
const auto &stmt :
module[
"body"])
1121 const std::string type = stmt.value(
"_type",
"");
1123 type ==
"Assign" && stmt[
"targets"].size() == 1 &&
1124 binds(stmt[
"targets"][0]))
1125 return &stmt[
"value"];
1127 type ==
"AnnAssign" && binds(stmt[
"target"]) && !stmt[
"value"].is_null())
1128 return &stmt[
"value"];
1133template <
typename JsonType>
1135 const std::string &var_name,
1136 const JsonType &block)
1139 auto visit = [&](
const JsonType &body,
const auto &self) ->
bool {
1140 for (
const auto &element : body)
1142 const auto &t = element[
"_type"];
1145 const bool is_ann = t ==
"AnnAssign" && element.contains(
"target") &&
1146 element[
"target"].contains(
"id") &&
1147 element[
"target"][
"id"] == var_name;
1149 const bool is_assign = t ==
"Assign" && element.contains(
"targets") &&
1150 !element[
"targets"].empty() &&
1151 element[
"targets"][0].contains(
"_type") &&
1152 element[
"targets"][0][
"_type"] ==
"Name" &&
1153 element[
"targets"][0].contains(
"id") &&
1154 element[
"targets"][0][
"id"] == var_name;
1156 const bool is_aug = t ==
"AugAssign" && element.contains(
"target") &&
1157 element[
"target"].contains(
"id") &&
1158 element[
"target"][
"id"] == var_name;
1159 if ((is_ann || is_assign || is_aug) && ++
count > 1)
1163 if (t ==
"FunctionDef" || t ==
"ClassDef" || t ==
"Lambda")
1167 for (
const auto &
key : {
"body",
"orelse",
"finalbody"})
1169 element.contains(
key) && element[
key].is_array() &&
1170 self(element[
key], self))
1174 if (element.contains(
"handlers") && element[
"handlers"].is_array())
1175 for (
const auto &h : element[
"handlers"])
1177 h.contains(
"body") && h[
"body"].is_array() && self(h[
"body"], self))
1181 if (element.contains(
"cases") && element[
"cases"].is_array())
1182 for (
const auto &c : element[
"cases"])
1184 c.contains(
"body") && c[
"body"].is_array() && self(c[
"body"], self))
1189 return block.contains(
"body") && block[
"body"].is_array() &&
1190 visit(block[
"body"], visit);
1193template <
typename JsonType>
1195 const std::string &var_name,
1197 const JsonType &ast)
1207 for (
int level =
static_cast<int>(function_path.size()) - 1; level >= 0;
1210 std::vector<std::string> partial_path(
1211 function_path.begin(), function_path.begin() + level + 1);
1213 if (!func_node.empty() && !
get_var_node(var_name, func_node).empty())
1221template <
typename JsonType>
1223 const JsonType &node,
1225 const JsonType &ast,
1229 node.contains(
"_type") && node[
"_type"] ==
"Constant" &&
1230 node.contains(
"value") && node[
"value"].is_number_integer())
1232 value = node[
"value"].template get<long long>();
1237 node.contains(
"_type") && node[
"_type"] ==
"UnaryOp" &&
1238 node.contains(
"operand") && node[
"operand"].contains(
"value") &&
1239 node[
"operand"][
"value"].is_number_integer() && node.contains(
"op"))
1241 const auto &op = node[
"op"];
1242 const bool is_usub =
1243 (op.is_object() && op.contains(
"_type") && op[
"_type"] ==
"USub") ||
1244 (op.is_string() && op ==
"USub");
1245 const bool is_uadd =
1246 (op.is_object() && op.contains(
"_type") && op[
"_type"] ==
"UAdd") ||
1247 (op.is_string() && op ==
"UAdd");
1249 if (is_usub || is_uadd)
1251 value = node[
"operand"][
"value"].template get<long long>();
1258 if (node.contains(
"_type") && node[
"_type"] ==
"Name" && node.contains(
"id"))
1260 const std::string var_name = node[
"id"].template get<std::string>();
1264 !var_value.empty() && var_value.contains(
"value") &&
1265 var_value[
"value"].contains(
"_type") &&
1266 var_value[
"value"][
"_type"] ==
"Constant" &&
1267 var_value[
"value"].contains(
"value") &&
1268 var_value[
"value"][
"value"].is_number_integer())
1270 value = var_value[
"value"][
"value"].template get<long long>();
1278template <
typename JsonType>
1283 list_value[
"_type"] ==
"List" && list_value.contains(
"elts") &&
1284 !list_value[
"elts"].empty())
1286 return list_value[
"elts"][
pos];
1290 if (list_value[
"_type"] ==
"BinOp")
1292 if (list_value[
"left"][
"_type"] ==
"List")
1293 return list_value[
"left"][
"elts"][
pos];
1294 if (list_value[
"right"][
"_type"] ==
"List")
1295 return list_value[
"right"][
"elts"][
pos];
1300 if (list_value[
"_type"] ==
"Subscript")
1305 if (list_value[
"_type"] ==
"Name")
1311template <
typename JsonType>
1314 for (
const auto &stmt : block)
1316 if (stmt.contains(
"_type") && stmt[
"_type"] ==
"Return")
1329 size_t last_at =
symbol_id.find_last_of(
'@');
1330 return (last_at != std::string::npos) ?
symbol_id.substr(last_at + 1)
1337template <
typename JsonType>
1340 const std::string &chars,
1341 const JsonType &loc_src)
1343 static constexpr const char *loc_keys[] = {
1344 "lineno",
"col_offset",
"end_lineno",
"end_col_offset"};
1345 auto copy_loc = [&](JsonType &node) {
1346 for (
const char *k : loc_keys)
1347 if (loc_src.contains(k))
1348 node[k] = loc_src[k];
1352 node[
"_type"] = kind;
1353 node[
"elts"] = JsonType::array();
1354 for (
const char ch : chars)
1357 elt[
"_type"] =
"Constant";
1358 elt[
"value"] = std::string(1, ch);
1360 node[
"elts"].push_back(elt);
1366template <
typename JsonType>
1370 if (!func_node.contains(
"decorator_list"))
1373 for (
const auto &decorator : func_node[
"decorator_list"])
1375 if (decorator[
"_type"] ==
"Name" && decorator[
"id"] ==
"overload")
1387template <
typename JsonType>
1391 if (!ast_json.contains(
"ast_output_dir") || !ast_json.contains(
"body"))
1394 const std::string output_dir =
1395 ast_json[
"ast_output_dir"].template get<std::string>();
1397 auto lookup = [&](
const std::string &module_name) -> std::string {
1398 std::ifstream f(output_dir +
"/" +
dotted_to_path(module_name) +
".json");
1401 JsonType module_json;
1403 if (!module_json.contains(
"body"))
1406 if (fn.empty() || !fn.contains(
"returns") || fn[
"returns"].is_null())
1411 for (
const auto &obj : ast_json[
"body"])
1413 if (obj[
"_type"] ==
"ImportFrom")
1415 if (obj[
"module"].is_null())
1417 const std::string r = lookup(obj[
"module"].
template get<std::string>());
1421 else if (obj[
"_type"] ==
"Import")
1423 for (
const auto &imported : obj[
"names"])
1425 const std::string r =
1426 lookup(imported[
"name"].
template get<std::string>());
1439 const nlohmann::json &node,
1440 std::vector<nlohmann::json> &values)
1442 if (!node.is_object() && !node.is_array())
1444 const std::string type = node.is_object() ? node.value(
"_type",
"") :
"";
1445 if (type ==
"FunctionDef" || type ==
"ClassDef" || type ==
"Lambda")
1447 if (type ==
"Return" && node.contains(
"value") && !node[
"value"].is_null())
1448 values.push_back(node[
"value"]);
1449 for (
const auto &child : node)
void base_type(type2tc &type, const namespacet &ns)
Definition base_type.cpp:6
static const twodig_t base
Definition bigint.cpp:28
int count
Definition cuda.h:51
@ full
Alpha-rename every symbol: the digest sees structure and types only.
Definition fingerprint.h:23
nlohmann::json json
Definition json.cpp:12
literalt pos(literalt a)
Definition literal.h:130
Definition json_utils.h:18
const JsonType get_var_node(const std::string &var_name, const JsonType &block)
Definition json_utils.h:704
JsonType find_class(const JsonType &ast_json, const std::string &class_name)
Definition json_utils.h:159
const JsonType find_var_decl(const std::string &var_name, const std::string &function, const JsonType &ast)
Definition json_utils.h:918
std::string dotted_name(const nlohmann::json &node)
The dotted name a Name or Attribute node spells, e.g. "collections.abc.Set".
Definition json_utils.h:611
const JsonType get_var_value(const std::string &var_name, const std::string &function, const JsonType &ast)
Definition json_utils.h:1050
std::string imported_function_return_type(const std::string &name, const JsonType &ast_json)
The declared return-type name of a function name defined in a module this AST imports,...
Definition json_utils.h:1389
std::vector< std::string > split_top_level_params(const std::string &s)
Split a rendered parameter list on commas that are not inside brackets, trimming each part.
Definition json_utils.h:982
bool ast_location_key(const std::string &k)
Definition json_utils.h:22
JsonType find_function_by_path(const JsonType &ast, const std::vector< std::string > &path)
Definition json_utils.h:834
bool ast_arrays_equal_ignoring_location(const nlohmann::json &a, const nlohmann::json &b)
Definition json_utils.h:55
bool extract_constant_integer(const JsonType &node, const std::string &function, const JsonType &ast, long long &value)
Definition json_utils.h:1222
bool any_class_defines_method(const JsonType &node, const std::string &name)
True when a class anywhere under node defines a method named name.
Definition json_utils.h:284
bool is_property_def(const JsonType &function_def)
Definition json_utils.h:256
void collect_return_values(const nlohmann::json &node, std::vector< nlohmann::json > &values)
Definition json_utils.h:1438
std::size_t binds_by_field(const nlohmann::json &node, const std::string &kind, const std::string &name)
Definition json_utils.h:1065
bool is_class(const std::string &name, const JsonType &ast_json)
Definition json_utils.h:441
std::string extract_var_name_from_symbol_id(const std::string &symbol_id)
Extract the variable name from a symbol identifier Examples: "py:test.py@l" -> "l" "py:test....
Definition json_utils.h:1327
bool ast_contains_call(const nlohmann::json &n)
True for X = Y between two bare names, such as _Elem = int.
Definition json_utils.h:89
JsonType find_var_in_function(const std::string &var_name, const JsonType &func_node)
Definition json_utils.h:888
std::size_t count_name_bindings(const nlohmann::json &node, const std::string &name)
Definition json_utils.h:1092
bool is_module(const std::string &module_name, const JsonType &ast)
Definition json_utils.h:511
std::string collections_abc_class(const nlohmann::json &ast, const std::string &name)
The collections.abc class that dotted name denotes, or empty.
Definition json_utils.h:662
bool ast_equal_ignoring_location(const nlohmann::json &a, const nlohmann::json &b)
Definition json_utils.h:74
const JsonType get_list_element(const JsonType &list_value, int pos)
Definition json_utils.h:1279
std::string get_annotation_type_name(const JsonType &annotation)
Definition json_utils.h:957
bool ast_objects_equal_ignoring_location(const nlohmann::json &a, const nlohmann::json &b)
Definition json_utils.h:34
bool is_name_alias(const nlohmann::json &stmt)
Definition json_utils.h:108
std::vector< std::string > split_function_path(const std::string &function)
Definition json_utils.h:792
bool any_class_has_property(const JsonType &ast_body, const std::string &name)
Definition json_utils.h:270
unsigned count_function_scope_classes(const JsonType &body, const std::string &class_name, bool in_function=false)
Counts the ClassDef nodes named class_name that sit inside a function body under body.
Definition json_utils.h:381
bool search_function_in_ast(const JsonType &node, const std::string &func_name)
Definition json_utils.h:125
bool is_imported_from(const JsonType &ast, const std::string &module, const std::string &entity)
True when from <module> import <entity> appears at the AST top level.
Definition json_utils.h:574
std::string render_annotation_type(const JsonType &annotation)
The full generic spelling of an annotation node, e.g.
Definition json_utils.h:1012
std::string constructed_attr_class(const Json &class_node, const std::string &attr)
C when the __init__ of class_node holds self.
Definition json_utils.h:229
JsonType & find_function_or_throw(JsonType &json, const std::string &func_name)
Throws std::runtime_error on a miss.
Definition json_utils.h:562
const std::string get_object_alias(const JsonType &ast, const std::string &obj_name)
Definition json_utils.h:675
std::string dotted_to_path(const std::string &module_name)
Convert a dotted Python module name to a filesystem path segment.
Definition json_utils.h:117
const JsonType * class_method_scope(const JsonType &body, std::string &name)
Definition json_utils.h:815
JsonType build_char_sequence_node(const char *kind, const std::string &chars, const JsonType &loc_src)
Definition json_utils.h:1338
bool has_overload_decorator(const JsonType &func_node)
Definition json_utils.h:1367
void collect_class_definition_lines(const JsonType &node, const std::string &class_name, std::vector< int > &lines)
Source lines of every ClassDef named class_name under node that the converter registers: at any scope...
Definition json_utils.h:407
std::size_t count_attr_stores(const Json &node, const std::string &attr, bool non_self_only)
Counts the stores and deletions of <obj>.
Definition json_utils.h:211
bool class_defines_method(const JsonType &ast_body, const std::string &class_name, const std::string &method_name)
True when class_name or one of its (transitive) base classes defines a method named method_name.
Definition json_utils.h:338
bool has_multiple_assignments_in_block(const std::string &var_name, const JsonType &block)
Definition json_utils.h:1134
bool is_property_method(const JsonType &ast_body, const std::string &class_name, const std::string &method_name)
Definition json_utils.h:306
const JsonType find_return_node(const JsonType &block)
Definition json_utils.h:1312
std::string resolve_import(const nlohmann::json &ast, const std::string &name)
What dotted name denotes through the module's imports, e.g.
Definition json_utils.h:637
const JsonType & find_imported_function(const JsonType &ast, const std::string &func_name)
Definition json_utils.h:596
JsonType try_find_function(const JsonType &json, const std::string &func_name)
Returns an empty JsonType on a miss. Never throws.
Definition json_utils.h:550
std::size_t count_class_defs(const JsonType &node)
Counts every ClassDef under node, at any depth.
Definition json_utils.h:366
Json find_attr_annotation(const Json &class_node, const std::string &attr)
The annotation of self.
Definition json_utils.h:173
const nlohmann::json * top_level_value(const nlohmann::json &module, const std::string &name)
Definition json_utils.h:1114
bool has_multiple_assignments_in_scope(const std::string &var_name, const std::string &function, const JsonType &ast)
Definition json_utils.h:1194
uint256_t key
Definition solidity_mapping.c:1
unsigned stack_budget_guardt< Tag >::depth
Definition stack_budget.h:72