revive_solc_json_interface/standard_json/output/error/
mod.rs1use std::collections::BTreeMap;
4
5use serde::Deserialize;
6use serde::Serialize;
7
8use crate::SolcStandardJsonInputSource;
9
10use self::mapped_location::MappedLocation;
11use self::source_location::SourceLocation;
12
13pub mod error_handler;
14pub mod mapped_location;
15pub mod source_location;
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct Error {
21 pub component: String,
23 pub error_code: Option<String>,
25 pub formatted_message: String,
27 pub message: String,
29 pub severity: String,
31 pub source_location: Option<SourceLocation>,
33 pub r#type: String,
35}
36
37impl Error {
38 pub const IGNORED_WARNING_CODES: [&'static str; 5] = ["1699", "3860", "5159", "5574", "6417"];
40
41 pub fn new<S>(
43 r#type: &str,
44 message: S,
45 source_location: Option<SourceLocation>,
46 sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
47 ) -> Self
48 where
49 S: std::fmt::Display,
50 {
51 let message = message.to_string();
52
53 let message_trimmed = message.trim();
54 let mut formatted_message = if message_trimmed.starts_with(r#type) {
55 message_trimmed.to_owned()
56 } else {
57 format!("{type}: {message_trimmed}")
58 };
59 formatted_message.push('\n');
60 if let Some(ref source_location) = source_location {
61 let source_code = sources.and_then(|sources| {
62 sources
63 .get(source_location.file.as_str())
64 .and_then(|source| source.content())
65 });
66 let mapped_location =
67 MappedLocation::try_from_source_location(source_location, source_code);
68 formatted_message.push_str(mapped_location.to_string().as_str());
69 formatted_message.push('\n');
70 }
71
72 Self {
73 component: "general".to_owned(),
74 error_code: None,
75 formatted_message,
76 message,
77 severity: r#type.to_lowercase(),
78 source_location,
79 r#type: r#type.to_owned(),
80 }
81 }
82
83 pub fn new_error<S>(
85 message: S,
86 source_location: Option<SourceLocation>,
87 sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
88 ) -> Self
89 where
90 S: std::fmt::Display,
91 {
92 Self::new("Error", message, source_location, sources)
93 }
94
95 pub fn new_warning<S>(
97 message: S,
98 source_location: Option<SourceLocation>,
99 sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
100 ) -> Self
101 where
102 S: std::fmt::Display,
103 {
104 Self::new("Warning", message, source_location, sources)
105 }
106
107 pub fn warning_send_and_transfer(
109 node: Option<&str>,
110 id_paths: &BTreeMap<usize, &String>,
111 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
112 ) -> Self {
113 let message = r#"
114Warning: It looks like you are using '<address payable>.send/transfer(<X>)'.
115Using '<address payable>.send/transfer(<X>)' is deprecated and strongly discouraged!
116The revive runtime uses a heuristic to detect '<address payable>.send/transfer(<X>)' calls and
117the gas stipend used by the runtime is different from the EVM.
118You are advised to carefully test this, employ re-entrancy guards or use the withdrawal pattern instead!
119Learn more on https://docs.soliditylang.org/en/latest/security-considerations.html#reentrancy
120and https://docs.soliditylang.org/en/latest/common-patterns.html#withdrawal-from-contracts
121"#
122 .to_owned();
123
124 Self::new_warning(
125 message,
126 node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
127 Some(sources),
128 )
129 }
130
131 pub fn warning_tx_origin(
133 node: Option<&str>,
134 id_paths: &BTreeMap<usize, &String>,
135 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
136 ) -> Self {
137 let message = r#"
138Warning: You are checking for 'tx.origin' in your code, which might lead to unexpected behavior.
139Polkadot comes with native account abstraction support, and therefore the initiator of a
140transaction might be different from the contract calling your code. It is highly recommended NOT
141to rely on tx.origin, but use msg.sender instead.
142"#
143 .to_owned();
144
145 Self::new_warning(
146 message,
147 node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
148 Some(sources),
149 )
150 }
151 pub fn error_runtime_code(
153 node: Option<&str>,
154 id_paths: &BTreeMap<usize, &String>,
155 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
156 ) -> Self {
157 let message = r#"
158Deploy and runtime code are merged in PVM, accessing `type(T).runtimeCode` is not possible.
159Please consider changing the functionality relying on reading runtime code to a different approach.
160"#;
161
162 Self::new_error(
163 message,
164 node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
165 Some(sources),
166 )
167 }
168
169 pub fn push_contract_path(&mut self, path: &str) {
171 self.formatted_message
172 .push_str(format!("\n--> {path}\n").as_str());
173 }
174
175 pub fn is_error(&self) -> bool {
177 self.severity == "error"
178 }
179
180 pub fn is_warning(&self) -> bool {
182 self.severity == "warning"
183 }
184}
185
186impl std::fmt::Display for Error {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 write!(f, "{}", self.formatted_message)
189 }
190}