use std::collections::BTreeMap;
use serde::Deserialize;
use serde::Serialize;
#[cfg(feature = "resolc")]
use crate::standard_json::input::settings::warning::Warning;
use crate::standard_json::output::error::error_handler::ErrorHandler;
#[cfg(feature = "resolc")]
use crate::SolcStandardJsonInputSettingsSelection;
#[cfg(feature = "resolc")]
use crate::SolcStandardJsonInputSource;
#[cfg(all(feature = "parallel", feature = "resolc"))]
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use self::contract::Contract;
use self::error::Error as SolcStandardJsonOutputError;
use self::source::Source;
pub mod contract;
pub mod error;
pub mod source;
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Output {
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub contracts: BTreeMap<String, BTreeMap<String, Contract>>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub sources: BTreeMap<String, Source>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub errors: Vec<SolcStandardJsonOutputError>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub long_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub revive_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolc_pipeline: Option<String>,
}
#[cfg(feature = "resolc")]
impl Output {
pub fn new(
sources: &BTreeMap<String, SolcStandardJsonInputSource>,
messages: &mut Vec<SolcStandardJsonOutputError>,
) -> Self {
let sources = sources
.iter()
.enumerate()
.map(|(index, (path, source))| {
(
path.to_owned(),
Source {
id: index,
ast: source
.content()
.map(|x| serde_json::to_value(x).unwrap())
.unwrap_or_default(),
},
)
})
.collect::<BTreeMap<String, Source>>();
Self {
contracts: BTreeMap::new(),
sources: sources.clone(),
errors: std::mem::take(messages),
version: None,
long_version: None,
revive_version: None,
resolc_pipeline: None,
}
}
pub fn new_with_messages(messages: Vec<SolcStandardJsonOutputError>) -> Self {
Self {
contracts: BTreeMap::new(),
sources: BTreeMap::new(),
errors: messages,
version: None,
long_version: None,
revive_version: None,
resolc_pipeline: None,
}
}
pub fn write_and_exit(
mut self,
selection_to_prune: SolcStandardJsonInputSettingsSelection,
) -> ! {
for (path, source) in self.sources.iter_mut() {
if selection_to_prune.contains(
path,
crate::SolcStandardJsonInputSettingsSelectionFileFlag::AST,
) {
source.ast = Default::default();
}
}
for (path, contracts) in self.contracts.iter_mut() {
for contract in contracts.values_mut() {
for &flag in crate::SolcStandardJsonInputSettingsSelectionFileFlag::all() {
if selection_to_prune.contains(path, flag) {
contract.reset_field_by_flag(flag);
}
}
}
}
self.contracts.retain(|_, contracts| {
contracts.retain(|_, contract| !contract.is_empty());
!contracts.is_empty()
});
serde_json::to_writer(std::io::stdout(), &self).expect("Stdout writing error");
std::process::exit(revive_common::EXIT_CODE_SUCCESS);
}
pub fn preprocess_ast(
&mut self,
sources: &BTreeMap<String, SolcStandardJsonInputSource>,
suppressed_warnings: &[Warning],
) -> anyhow::Result<()> {
let id_paths: BTreeMap<usize, &String> = self
.sources
.iter()
.map(|(path, source)| (source.id, path))
.collect();
#[cfg(feature = "parallel")]
let iter = self.sources.par_iter();
#[cfg(not(feature = "parallel"))]
let iter = self.sources.iter();
let messages: Vec<SolcStandardJsonOutputError> = iter
.flat_map(|(_path, source)| {
Source::get_messages(&source.ast, &id_paths, sources, suppressed_warnings)
})
.collect();
self.errors.extend(messages);
Ok(())
}
pub fn push_error(&mut self, path: Option<String>, error: anyhow::Error) {
use crate::standard_json::output::error::source_location::SourceLocation;
self.errors.push(SolcStandardJsonOutputError::new_error(
error,
path.map(SourceLocation::new),
None,
));
}
}
impl ErrorHandler for Output {
fn errors(&self) -> Vec<&SolcStandardJsonOutputError> {
self.errors
.iter()
.filter(|error| error.is_error())
.collect()
}
fn take_warnings(&mut self) -> Vec<SolcStandardJsonOutputError> {
let warnings = self
.errors
.iter()
.filter(|message| message.is_warning())
.cloned()
.collect();
self.errors.retain(|message| !message.is_warning());
warnings
}
}