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