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(all(feature = "parallel", feature = "resolc"))]
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 .iter()
60 .enumerate()
61 .map(|(index, (path, source))| {
62 (
63 path.to_owned(),
64 Source {
65 id: index,
66 ast: source.content().map(|x| serde_json::to_value(x).unwrap()),
67 },
68 )
69 })
70 .collect::<BTreeMap<String, Source>>();
71
72 Self {
73 contracts: BTreeMap::new(),
74 sources: sources.clone(),
75 errors: std::mem::take(messages),
76
77 version: None,
78 long_version: None,
79 revive_version: None,
80 }
81 }
82
83 pub fn new_with_messages(messages: Vec<SolcStandardJsonOutputError>) -> Self {
87 Self {
88 contracts: BTreeMap::new(),
89 sources: BTreeMap::new(),
90 errors: messages,
91
92 version: None,
93 long_version: None,
94 revive_version: None,
95 }
96 }
97
98 pub fn write_and_exit(
100 mut self,
101 selection_to_prune: SolcStandardJsonInputSettingsSelection,
102 ) -> ! {
103 for (path, contracts) in self.contracts.iter_mut() {
104 for contract in contracts.values_mut() {
105 if selection_to_prune.contains(
106 path,
107 &crate::SolcStandardJsonInputSettingsSelectionFileFlag::Metadata,
108 ) {
109 contract.metadata = serde_json::Value::Null;
110 }
111 if selection_to_prune.contains(
112 path,
113 &crate::SolcStandardJsonInputSettingsSelectionFileFlag::Yul,
114 ) {
115 contract.ir_optimized = String::new();
116 }
117 if let Some(ref mut evm) = contract.evm {
118 if selection_to_prune.contains(
119 path,
120 &crate::SolcStandardJsonInputSettingsSelectionFileFlag::MethodIdentifiers,
121 ) {
122 evm.method_identifiers.clear();
123 }
124 }
125 }
126 }
127
128 self.contracts.retain(|_, contracts| {
129 contracts.retain(|_, contract| !contract.is_empty());
130 !contracts.is_empty()
131 });
132
133 serde_json::to_writer(std::io::stdout(), &self).expect("Stdout writing error");
134 std::process::exit(revive_common::EXIT_CODE_SUCCESS);
135 }
136
137 pub fn preprocess_ast(
139 &mut self,
140 sources: &BTreeMap<String, SolcStandardJsonInputSource>,
141 suppressed_warnings: &[Warning],
142 ) -> anyhow::Result<()> {
143 let id_paths: BTreeMap<usize, &String> = self
144 .sources
145 .iter()
146 .map(|(path, source)| (source.id, path))
147 .collect();
148
149 #[cfg(feature = "parallel")]
150 let iter = self.sources.par_iter();
151 #[cfg(not(feature = "parallel"))]
152 let iter = self.sources.iter();
153
154 let messages: Vec<SolcStandardJsonOutputError> = iter
155 .flat_map(|(_path, source)| {
156 source
157 .ast
158 .as_ref()
159 .map(|ast| Source::get_messages(ast, &id_paths, sources, suppressed_warnings))
160 .unwrap_or_default()
161 })
162 .collect();
163 self.errors.extend(messages);
164
165 Ok(())
166 }
167
168 pub fn push_error(&mut self, path: Option<String>, error: anyhow::Error) {
172 use crate::standard_json::output::error::source_location::SourceLocation;
173
174 self.errors.push(SolcStandardJsonOutputError::new_error(
175 error,
176 path.map(SourceLocation::new),
177 None,
178 ));
179 }
180}
181
182impl ErrorHandler for Output {
183 fn errors(&self) -> Vec<&SolcStandardJsonOutputError> {
184 self.errors
185 .iter()
186 .filter(|error| error.is_error())
187 .collect()
188 }
189
190 fn take_warnings(&mut self) -> Vec<SolcStandardJsonOutputError> {
191 let warnings = self
192 .errors
193 .iter()
194 .filter(|message| message.is_warning())
195 .cloned()
196 .collect();
197 self.errors.retain(|message| !message.is_warning());
198 warnings
199 }
200}