revive_solc_json_interface/standard_json/output/
source.rs1#[cfg(feature = "resolc")]
4use std::collections::BTreeMap;
5
6use serde::Deserialize;
7use serde::Serialize;
8
9#[cfg(feature = "resolc")]
10use crate::standard_json::input::settings::warning::Warning;
11#[cfg(feature = "resolc")]
12use crate::standard_json::output::error::Error as SolcStandardJsonOutputError;
13#[cfg(feature = "resolc")]
14use crate::SolcStandardJsonInputSource;
15
16#[derive(Debug, Serialize, Deserialize, Clone)]
18#[serde(rename_all = "camelCase")]
19pub struct Source {
20 pub id: usize,
22 #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
24 pub ast: serde_json::Value,
25}
26
27#[cfg(feature = "resolc")]
28impl Source {
29 pub fn new(id: usize) -> Self {
33 Self {
34 id,
35 ast: Default::default(),
36 }
37 }
38
39 pub fn check_send_and_transfer(
41 ast: &serde_json::Value,
42 id_paths: &BTreeMap<usize, &String>,
43 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
44 ) -> Option<SolcStandardJsonOutputError> {
45 let ast = ast.as_object()?;
46
47 (ast.get("nodeType")?.as_str()? == "FunctionCall").then_some(())?;
48
49 let expression = ast.get("expression")?.as_object()?;
50 (expression.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
51 let member_name = expression.get("memberName")?.as_str()?;
52 ["send", "transfer"].contains(&member_name).then_some(())?;
53
54 let expression = expression.get("expression")?.as_object()?;
55 let type_descriptions = expression.get("typeDescriptions")?.as_object()?;
56 let type_identifier = type_descriptions.get("typeIdentifier")?.as_str()?;
57 ["t_address_payable"]
58 .contains(&type_identifier)
59 .then_some(())?;
60
61 Some(Warning::SendAndTransfer.as_error(ast.get("src")?.as_str(), id_paths, sources))
62 }
63
64 pub fn check_runtime_code(
66 ast: &serde_json::Value,
67 id_paths: &BTreeMap<usize, &String>,
68 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
69 ) -> Option<SolcStandardJsonOutputError> {
70 let ast = ast.as_object()?;
71
72 (ast.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
73 (ast.get("memberName")?.as_str()? == "runtimeCode").then_some(())?;
74
75 let expression = ast.get("expression")?.as_object()?;
76 let type_descriptions = expression.get("typeDescriptions")?.as_object()?;
77 type_descriptions
78 .get("typeIdentifier")?
79 .as_str()?
80 .starts_with("t_magic_meta_type")
81 .then_some(())?;
82
83 Some(SolcStandardJsonOutputError::error_runtime_code(
84 ast.get("src")?.as_str(),
85 id_paths,
86 sources,
87 ))
88 }
89
90 pub fn check_tx_origin(
92 ast: &serde_json::Value,
93 id_paths: &BTreeMap<usize, &String>,
94 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
95 ) -> Option<SolcStandardJsonOutputError> {
96 let ast = ast.as_object()?;
97
98 (ast.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
99 (ast.get("memberName")?.as_str()? == "origin").then_some(())?;
100
101 let expression = ast.get("expression")?.as_object()?;
102 (expression.get("nodeType")?.as_str()? == "Identifier").then_some(())?;
103 (expression.get("name")?.as_str()? == "tx").then_some(())?;
104
105 Some(Warning::TxOrigin.as_error(ast.get("src")?.as_str(), id_paths, sources))
106 }
107
108 #[cfg(feature = "resolc")]
110 pub fn get_messages(
111 ast: &serde_json::Value,
112 id_paths: &BTreeMap<usize, &String>,
113 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
114 suppressed_warnings: &[Warning],
115 ) -> Vec<SolcStandardJsonOutputError> {
116 let mut messages = Vec::new();
117 if !suppressed_warnings.contains(&Warning::SendAndTransfer) {
118 if let Some(message) = Self::check_send_and_transfer(ast, id_paths, sources) {
119 messages.push(message);
120 }
121 }
122 if !suppressed_warnings.contains(&Warning::TxOrigin) {
123 if let Some(message) = Self::check_tx_origin(ast, id_paths, sources) {
124 messages.push(message);
125 }
126 }
127 if let Some(message) = Self::check_runtime_code(ast, id_paths, sources) {
128 messages.push(message);
129 }
130
131 match ast {
132 serde_json::Value::Array(array) => {
133 for element in array.iter() {
134 messages.extend(Self::get_messages(
135 element,
136 id_paths,
137 sources,
138 suppressed_warnings,
139 ));
140 }
141 }
142 serde_json::Value::Object(object) => {
143 for (_key, value) in object.iter() {
144 messages.extend(Self::get_messages(
145 value,
146 id_paths,
147 sources,
148 suppressed_warnings,
149 ));
150 }
151 }
152 _ => {}
153 }
154
155 messages
156 }
157}