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