revive_solc_json_interface/standard_json/output/
mod.rs1use std::collections::BTreeMap;
4
5use serde::Deserialize;
6use serde::Serialize;
7
8#[cfg(feature = "resolc")]
9use crate::standard_json::input::settings::warning::Warning;
10use crate::standard_json::output::error::error_handler::ErrorHandler;
11#[cfg(feature = "resolc")]
12use crate::SolcStandardJsonInputSettingsSelection;
13#[cfg(feature = "resolc")]
14use crate::SolcStandardJsonInputSource;
15#[cfg(feature = "parallel")]
16use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
17
18use self::contract::Contract;
19use self::error::Error as SolcStandardJsonOutputError;
20use self::source::Source;
21
22pub mod contract;
23pub mod error;
24pub mod source;
25
26#[derive(Debug, Serialize, Deserialize, Clone, Default)]
28pub struct Output {
29 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
31 pub contracts: BTreeMap<String, BTreeMap<String, Contract>>,
32 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
34 pub sources: BTreeMap<String, Source>,
35 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 pub errors: Vec<SolcStandardJsonOutputError>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub version: Option<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub long_version: Option<String>,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub revive_version: Option<String>,
47}
48
49#[cfg(feature = "resolc")]
50impl Output {
51 pub fn new(
55 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
56 messages: &mut Vec<SolcStandardJsonOutputError>,
57 ) -> Self {
58 let sources = sources
59 .keys()
60 .enumerate()
61 .map(|(index, path)| (path.to_owned(), Source::new(index)))
62 .collect::<BTreeMap<String, Source>>();
63
64 Self {
65 contracts: BTreeMap::new(),
66 sources,
67 errors: std::mem::take(messages),
68
69 version: None,
70 long_version: None,
71 revive_version: None,
72 }
73 }
74
75 pub fn new_with_messages(messages: Vec<SolcStandardJsonOutputError>) -> Self {
79 Self {
80 contracts: BTreeMap::new(),
81 sources: BTreeMap::new(),
82 errors: messages,
83
84 version: None,
85 long_version: None,
86 revive_version: None,
87 }
88 }
89
90 pub fn write_and_exit(
92 mut self,
93 selection_to_prune: SolcStandardJsonInputSettingsSelection,
94 ) -> ! {
95 let sources = self.sources.values_mut().collect::<Vec<&mut Source>>();
96 for source in sources.into_iter() {
97 if selection_to_prune
98 .contains(&crate::SolcStandardJsonInputSettingsSelectionFileFlag::AST)
99 {
100 source.ast = None;
101 }
102 }
103
104 let contracts = self
105 .contracts
106 .values_mut()
107 .flat_map(|contracts| contracts.values_mut())
108 .collect::<Vec<&mut Contract>>();
109 for contract in contracts.into_iter() {
110 if selection_to_prune
111 .contains(&crate::SolcStandardJsonInputSettingsSelectionFileFlag::Metadata)
112 {
113 contract.metadata = serde_json::Value::Null;
114 }
115 if selection_to_prune
116 .contains(&crate::SolcStandardJsonInputSettingsSelectionFileFlag::Yul)
117 {
118 contract.ir_optimized = String::new();
119 }
120 if let Some(ref mut evm) = contract.evm {
121 if selection_to_prune.contains(
122 &crate::SolcStandardJsonInputSettingsSelectionFileFlag::MethodIdentifiers,
123 ) {
124 evm.method_identifiers.clear();
125 }
126 }
127 }
128
129 self.contracts.retain(|_, contracts| {
130 contracts.retain(|_, contract| !contract.is_empty());
131 !contracts.is_empty()
132 });
133
134 serde_json::to_writer(std::io::stdout(), &self).expect("Stdout writing error");
135 std::process::exit(revive_common::EXIT_CODE_SUCCESS);
136 }
137
138 pub fn preprocess_ast(
140 &mut self,
141 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
142 suppressed_warnings: &[Warning],
143 ) -> anyhow::Result<()> {
144 let id_paths: BTreeMap<usize, &String> = self
145 .sources
146 .iter()
147 .map(|(path, source)| (source.id, path))
148 .collect();
149
150 #[cfg(feature = "parallel")]
151 let iter = self.sources.par_iter();
152 #[cfg(not(feature = "parallel"))]
153 let iter = self.sources.iter();
154
155 let messages: Vec<SolcStandardJsonOutputError> = iter
156 .flat_map(|(_path, source)| {
157 source
158 .ast
159 .as_ref()
160 .map(|ast| Source::get_messages(ast, &id_paths, sources, suppressed_warnings))
161 .unwrap_or_default()
162 })
163 .collect();
164 self.errors.extend(messages);
165
166 Ok(())
167 }
168
169 pub fn push_error(&mut self, path: Option<String>, error: anyhow::Error) {
173 use crate::standard_json::output::error::source_location::SourceLocation;
174
175 self.errors.push(SolcStandardJsonOutputError::new_error(
176 error,
177 path.map(SourceLocation::new),
178 None,
179 ));
180 }
181}
182
183impl ErrorHandler for Output {
184 fn errors(&self) -> Vec<&SolcStandardJsonOutputError> {
185 self.errors
186 .iter()
187 .filter(|error| error.is_error())
188 .collect()
189 }
190
191 fn take_warnings(&mut self) -> Vec<SolcStandardJsonOutputError> {
192 let warnings = self
193 .errors
194 .iter()
195 .filter(|message| message.is_warning())
196 .cloned()
197 .collect();
198 self.errors.retain(|message| !message.is_warning());
199 warnings
200 }
201}