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 pub ast: Option<serde_json::Value>,
24}
25
26#[cfg(feature = "resolc")]
27impl Source {
28 pub fn new(id: usize) -> Self {
32 Self { id, ast: None }
33 }
34
35 pub fn check_send_and_transfer(
37 ast: &serde_json::Value,
38 id_paths: &BTreeMap<usize, &String>,
39 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
40 ) -> Option<SolcStandardJsonOutputError> {
41 let ast = ast.as_object()?;
42
43 (ast.get("nodeType")?.as_str()? == "FunctionCall").then_some(())?;
44
45 let expression = ast.get("expression")?.as_object()?;
46 (expression.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
47 let member_name = expression.get("memberName")?.as_str()?;
48 ["send", "transfer"].contains(&member_name).then_some(())?;
49
50 let expression = expression.get("expression")?.as_object()?;
51 let type_descriptions = expression.get("typeDescriptions")?.as_object()?;
52 let type_identifier = type_descriptions.get("typeIdentifier")?.as_str()?;
53 ["t_address_payable"]
54 .contains(&type_identifier)
55 .then_some(())?;
56
57 Some(Warning::SendAndTransfer.as_error(ast.get("src")?.as_str(), id_paths, sources))
58 }
59
60 pub fn check_runtime_code(
62 ast: &serde_json::Value,
63 id_paths: &BTreeMap<usize, &String>,
64 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
65 ) -> Option<SolcStandardJsonOutputError> {
66 let ast = ast.as_object()?;
67
68 (ast.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
69 (ast.get("memberName")?.as_str()? == "runtimeCode").then_some(())?;
70
71 let expression = ast.get("expression")?.as_object()?;
72 let type_descriptions = expression.get("typeDescriptions")?.as_object()?;
73 type_descriptions
74 .get("typeIdentifier")?
75 .as_str()?
76 .starts_with("t_magic_meta_type")
77 .then_some(())?;
78
79 Some(SolcStandardJsonOutputError::error_runtime_code(
80 ast.get("src")?.as_str(),
81 id_paths,
82 sources,
83 ))
84 }
85
86 pub fn check_tx_origin(
88 ast: &serde_json::Value,
89 id_paths: &BTreeMap<usize, &String>,
90 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
91 ) -> Option<SolcStandardJsonOutputError> {
92 let ast = ast.as_object()?;
93
94 (ast.get("nodeType")?.as_str()? == "MemberAccess").then_some(())?;
95 (ast.get("memberName")?.as_str()? == "origin").then_some(())?;
96
97 let expression = ast.get("expression")?.as_object()?;
98 (expression.get("nodeType")?.as_str()? == "Identifier").then_some(())?;
99 (expression.get("name")?.as_str()? == "tx").then_some(())?;
100
101 Some(Warning::TxOrigin.as_error(ast.get("src")?.as_str(), id_paths, sources))
102 }
103
104 #[cfg(feature = "resolc")]
106 pub fn get_messages(
107 ast: &serde_json::Value,
108 id_paths: &BTreeMap<usize, &String>,
109 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
110 suppressed_warnings: &[Warning],
111 ) -> Vec<SolcStandardJsonOutputError> {
112 let mut messages = Vec::new();
113 if !suppressed_warnings.contains(&Warning::SendAndTransfer) {
114 if let Some(message) = Self::check_send_and_transfer(ast, id_paths, sources) {
115 messages.push(message);
116 }
117 }
118 if !suppressed_warnings.contains(&Warning::TxOrigin) {
119 if let Some(message) = Self::check_tx_origin(ast, id_paths, sources) {
120 messages.push(message);
121 }
122 }
123 if let Some(message) = Self::check_runtime_code(ast, id_paths, sources) {
124 messages.push(message);
125 }
126
127 match ast {
128 serde_json::Value::Array(array) => {
129 for element in array.iter() {
130 messages.extend(Self::get_messages(
131 element,
132 id_paths,
133 sources,
134 suppressed_warnings,
135 ));
136 }
137 }
138 serde_json::Value::Object(object) => {
139 for (_key, value) in object.iter() {
140 messages.extend(Self::get_messages(
141 value,
142 id_paths,
143 sources,
144 suppressed_warnings,
145 ));
146 }
147 }
148 _ => {}
149 }
150
151 messages
152 }
153}