3#include <nlohmann/json.hpp>
5#include <unordered_map>
6#include <unordered_set>
16inline std::pair<std::string, std::string>
20 func.value(
"_type",
"") !=
"Attribute" || !func.contains(
"value") ||
21 func[
"value"].value(
"_type",
"") !=
"Name")
22 return {func.value(
"id",
""), func.value(
"id",
"")};
23 const std::string attr = func.value(
"attr",
"");
24 return {func[
"value"].value(
"id",
"") +
"." + attr, attr};
32 if (type ==
"int" || type ==
"bool")
34 return type ==
"float" ?
"float" :
"";
40 return leaf.rfind(
"nondet_", 0) == 0 ?
scalar_name_kind(leaf.substr(7)) :
"";
48 if (lit.is_number_integer() || lit.is_boolean())
50 return lit.is_number_float() ?
"float" :
"";
61 const nlohmann::json &
value,
62 const nlohmann::json &module_body = nlohmann::json())
64 if (
value.value(
"_type",
"") ==
"Constant" &&
value.contains(
"value"))
69 if (
value.value(
"_type",
"") !=
"Call" || !
value.contains(
"func"))
74 if (!nondet_kind.empty())
77 if (module_body.is_array())
79 for (
const auto &stmt : module_body)
82 !stmt.is_object() || stmt.value(
"_type",
"") !=
"FunctionDef" ||
83 stmt.value(
"name",
"") != callee || !stmt.contains(
"returns") ||
84 stmt[
"returns"].is_null())
87 const std::string ret_kind =
89 if (!ret_kind.empty())
105 static bool possible =
false;
111 const bool int_float_only =
112 kinds.size() == 2 && kinds.count(
"num") && kinds.count(
"float");
113 const bool diverge = kinds.size() >= 2 && !int_float_only;
114 if (diverge && kinds.count(
"float"))
121 const std::string &name,
122 const nlohmann::json &scope_body,
123 const nlohmann::json &module_body = nlohmann::json())
125 if (!scope_body.is_array())
129 for (
const auto &stmt : scope_body)
131 if (!stmt.is_object())
134 const std::string stmt_type = stmt.value(
"_type",
"");
135 nlohmann::json target;
136 if (stmt_type ==
"Assign")
138 if (!stmt.contains(
"targets") || stmt[
"targets"].size() != 1)
140 target = stmt[
"targets"][0];
142 else if (stmt_type ==
"AnnAssign")
144 if (!stmt.contains(
"target"))
146 target = stmt[
"target"];
151 if (target.value(
"_type",
"") !=
"Name" || target.value(
"id",
"") != name)
154 if (!stmt.contains(
"value") || stmt[
"value"].is_null())
165 if (target.value(
"_type",
"") ==
"Name")
166 return target.value(
"id",
"");
168 target.value(
"_type",
"") ==
"Attribute" && target.contains(
"value") &&
169 target[
"value"].value(
"_type",
"") ==
"Name")
170 return target[
"value"].value(
"id",
"") +
"." + target.value(
"attr",
"");
176inline std::unordered_map<std::string, std::string>
178 const nlohmann::json &block,
179 const nlohmann::json &scope_body,
180 const nlohmann::json &module_body = nlohmann::json())
182 std::unordered_map<std::string, std::string> types;
183 if (!block.is_array())
186 for (
const auto &stmt : block)
188 if (!stmt.is_object())
191 const std::string stmt_type = stmt.value(
"_type",
"");
192 nlohmann::json target;
193 if (stmt_type ==
"Assign")
195 if (!stmt.contains(
"targets") || stmt[
"targets"].size() != 1)
197 target = stmt[
"targets"][0];
199 else if (stmt_type ==
"AnnAssign")
201 if (!stmt.contains(
"target"))
203 target = stmt[
"target"];
213 if (!stmt.contains(
"value") || stmt[
"value"].is_null())
218 const auto &
value = stmt[
"value"];
221 kind.empty() &&
value.value(
"_type",
"") ==
"Name" &&
222 value.contains(
"id"))
224 value[
"id"].get<std::string>(), scope_body, module_body);
239 const nlohmann::json &block,
240 std::unordered_map<std::string, std::unordered_set<std::string>> &kinds,
241 std::unordered_map<std::string, int> &leaf_count,
243 const nlohmann::json &scope_body,
244 const nlohmann::json &module_body = nlohmann::json())
247 block.is_array() && block.size() == 1 && block[0].is_object() &&
248 block[0].value(
"_type",
"") ==
"If")
250 const auto &nested = block[0];
252 !nested.contains(
"body") || !nested.contains(
"orelse") ||
253 nested[
"orelse"].empty())
273 for (
const auto &[name, kind] :
276 kinds[name].insert(kind);
284 const nlohmann::json &if_node,
285 std::unordered_map<std::string, std::unordered_set<std::string>> &kinds,
286 std::unordered_map<std::string, int> &leaf_count,
288 const nlohmann::json &scope_body,
289 const nlohmann::json &module_body = nlohmann::json())
291 if (!if_node.contains(
"body"))
293 if (!if_node.contains(
"orelse") || if_node[
"orelse"].empty())
313inline bool assigns_name(
const nlohmann::json &stmt,
const std::string &name)
315 const std::string kind = stmt.value(
"_type",
"");
316 const nlohmann::json *target =
nullptr;
317 if (kind ==
"AnnAssign")
318 target = &stmt[
"target"];
319 else if (kind ==
"Assign" && stmt[
"targets"].size() == 1)
320 target = &stmt[
"targets"][0];
321 return target && target->is_object() &&
322 target->value(
"_type",
"") ==
"Name" &&
323 target->value(
"id",
"") == name;
329 const nlohmann::json &
value,
330 const nlohmann::json &module_body)
333 !
value.is_object() ||
value.value(
"_type",
"") !=
"IfExp" ||
334 !
value.contains(
"body") || !
value.contains(
"orelse"))
336 const std::string then_kind =
338 const std::string else_kind =
340 return !then_kind.empty() && !else_kind.empty() &&
348 const std::string &name,
349 const nlohmann::json &scope_body,
350 const nlohmann::json &module_body = nlohmann::json())
352 if (!scope_body.is_array())
355 for (
const auto &stmt : scope_body)
357 if (!stmt.is_object())
363 if (stmt.value(
"_type",
"") !=
"If")
366 std::unordered_map<std::string, std::unordered_set<std::string>> kinds;
367 std::unordered_map<std::string, int> leaf_count;
370 stmt, kinds, leaf_count, leaf_total, scope_body, module_body))
373 auto it = kinds.find(name);
375 it != kinds.end() && leaf_count[name] == leaf_total &&
398 const nlohmann::json &annotation = stmt.value(
"annotation", nlohmann::json());
399 const std::string type =
400 annotation.is_object() ? annotation.value(
"id",
"") :
"";
401 if (type ==
"int" || type ==
"bool")
403 return type ==
"float" ?
"float" :
"";
409 const auto it = node.find(
key);
410 return it != node.end() && it->is_number_integer() ? it->get<
int>() : -1;
422inline bool loop_spans(
const nlohmann::json &stmt,
int before)
424 const std::string kind = stmt.value(
"_type",
"");
425 const int end =
line_field(stmt,
"end_lineno");
426 return (kind ==
"While" || kind ==
"For" || kind ==
"AsyncFor") &&
427 line_field(stmt,
"lineno") <= before && (end < 0 || end >= before);
434 const nlohmann::json &stmt,
435 const std::string &name,
438 std::vector<numeric_bindingt> &bindings)
441 if (!nested && line >= 0 && line < before &&
assigns_name(stmt, name))
444 if (!
number.empty() && stmt.contains(
"value") && !stmt[
"value"].is_null())
445 bindings.push_back({
number, stmt[
"value"], nested});
452 const nlohmann::json &body,
453 const std::string &name,
457 std::vector<numeric_bindingt> &bindings)
459 for (
const auto &stmt : body)
461 if (!stmt.is_object() || (!include_later &&
starts_after(stmt, before)))
463 const std::string kind = stmt.value(
"_type",
"");
464 if (kind ==
"FunctionDef" || kind ==
"ClassDef")
467 const bool later = include_later ||
loop_spans(stmt, before);
468 for (
const char *
key : {
"body",
"orelse",
"finalbody",
"handlers",
"cases"})
469 if (stmt.contains(
key) && stmt[
key].is_array())
471 stmt[
key], name,
true, before, later, bindings);
481 bool has_int =
false, has_float =
false, in_block =
false;
482 for (
const auto &binding : bindings)
484 has_int |= binding.kind ==
"int";
485 has_float |= binding.kind ==
"float";
486 in_block |= binding.in_block;
488 return has_int && has_float && in_block;
Definition literal_divergence.h:13
bool ifexp_arms_diverge(const nlohmann::json &value, const nlohmann::json &module_body)
Definition literal_divergence.h:328
std::string nondet_leaf_kind(const std::string &leaf)
Definition literal_divergence.h:38
bool collect_branch_literal_kinds(const nlohmann::json &block, std::unordered_map< std::string, std::unordered_set< std::string > > &kinds, std::unordered_map< std::string, int > &leaf_count, int &leaf_total, const nlohmann::json &scope_body, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:238
std::string scalar_name_kind(const std::string &type)
Definition literal_divergence.h:28
bool collect_if_node_literal_kinds(const nlohmann::json &if_node, std::unordered_map< std::string, std::unordered_set< std::string > > &kinds, std::unordered_map< std::string, int > &leaf_count, int &leaf_total, const nlohmann::json &scope_body, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:283
std::string constant_kind(const nlohmann::json &lit)
Definition literal_divergence.h:44
bool & float_tags_possible()
Definition literal_divergence.h:103
std::string classify_literal_value_kind(const nlohmann::json &value, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:60
bool kinds_diverge(const std::unordered_set< std::string > &kinds)
Definition literal_divergence.h:109
bool scope_assigns_divergent_literal_types(const std::string &name, const nlohmann::json &scope_body, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:347
void record_numeric_binding(const nlohmann::json &stmt, const std::string &name, bool nested, int before, std::vector< numeric_bindingt > &bindings)
Definition literal_divergence.h:433
std::string classify_name_kind(const std::string &name, const nlohmann::json &scope_body, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:120
bool is_path_dependent_number(const std::vector< numeric_bindingt > &bindings)
Definition literal_divergence.h:479
bool loop_spans(const nlohmann::json &stmt, int before)
Definition literal_divergence.h:422
bool assigns_name(const nlohmann::json &stmt, const std::string &name)
Definition literal_divergence.h:313
std::pair< std::string, std::string > callee_names(const nlohmann::json &func)
Definition literal_divergence.h:17
std::string assigned_name(const nlohmann::json &target)
Definition literal_divergence.h:163
void collect_numeric_bindings(const nlohmann::json &body, const std::string &name, bool nested, int before, bool include_later, std::vector< numeric_bindingt > &bindings)
Definition literal_divergence.h:451
std::string numeric_binding_kind(const nlohmann::json &stmt, const std::string &name)
Definition literal_divergence.h:394
std::unordered_map< std::string, std::string > classify_branch_literal_assigns(const nlohmann::json &block, const nlohmann::json &scope_body, const nlohmann::json &module_body=nlohmann::json())
Definition literal_divergence.h:177
bool starts_after(const nlohmann::json &stmt, int before)
Definition literal_divergence.h:415
int line_field(const nlohmann::json &node, const char *key)
Definition literal_divergence.h:407
void * value
Definition solidity_mapping.c:2
uint256_t key
Definition solidity_mapping.c:1
Definition literal_divergence.h:385
nlohmann::json value
Definition literal_divergence.h:387
std::string kind
Definition literal_divergence.h:386
bool in_block
Definition literal_divergence.h:388