foundry_cli/opts/build/
utils.rs

1use eyre::Result;
2use foundry_compilers::{
3    CompilerInput, Graph, Project,
4    artifacts::{Source, Sources},
5    multi::{MultiCompilerLanguage, MultiCompilerParser},
6    solc::{SolcLanguage, SolcVersionedInput},
7};
8use foundry_config::Config;
9use rayon::prelude::*;
10use solar::sema::ParsingContext;
11use std::path::PathBuf;
12
13/// Configures a [`ParsingContext`] from [`Config`].
14///
15/// - Configures include paths, remappings
16/// - Source files are added if `add_source_file` is set
17/// - If no `project` is provided, it will spin up a new ephemeral project.
18/// - If no `target_paths` are provided, all project files are processed.
19/// - Only processes the subset of sources with the most up-to-date Solidity version.
20pub fn configure_pcx(
21    pcx: &mut ParsingContext<'_>,
22    config: &Config,
23    project: Option<&Project>,
24    target_paths: Option<&[PathBuf]>,
25) -> Result<()> {
26    // Process build options
27    let project = match project {
28        Some(project) => project,
29        None => &config.ephemeral_project()?,
30    };
31
32    let sources = match target_paths {
33        // If target files are provided, only process those sources
34        Some(targets) => {
35            let mut sources = Sources::new();
36            for t in targets {
37                let path = dunce::canonicalize(t)?;
38                let source = Source::read(&path)?;
39                sources.insert(path, source);
40            }
41            sources
42        }
43        // Otherwise, process all project files
44        None => project.paths.read_input_files()?,
45    };
46
47    // Only process sources with latest Solidity version to avoid conflicts.
48    let graph = Graph::<MultiCompilerParser>::resolve_sources(&project.paths, sources)?;
49    let (version, sources, _) = graph
50        // resolve graph into mapping language -> version -> sources
51        .into_sources_by_version(project)?
52        .sources
53        .into_iter()
54        // only interested in Solidity sources
55        .find(|(lang, _)| *lang == MultiCompilerLanguage::Solc(SolcLanguage::Solidity))
56        .ok_or_else(|| eyre::eyre!("no Solidity sources"))?
57        .1
58        .into_iter()
59        // always pick the latest version
60        .max_by(|(v1, _, _), (v2, _, _)| v1.cmp(v2))
61        .unwrap();
62
63    let solc = SolcVersionedInput::build(
64        sources,
65        config.solc_settings()?,
66        SolcLanguage::Solidity,
67        version,
68    );
69
70    configure_pcx_from_solc(pcx, project, &solc, true);
71
72    Ok(())
73}
74
75/// Configures a [`ParsingContext`] from a [`Project`] and [`SolcVersionedInput`].
76///
77/// - Configures include paths, remappings.
78/// - Source files are added if `add_source_file` is set
79pub fn configure_pcx_from_solc(
80    pcx: &mut ParsingContext<'_>,
81    project: &Project,
82    vinput: &SolcVersionedInput,
83    add_source_files: bool,
84) {
85    configure_pcx_from_solc_cli(pcx, project, &vinput.cli_settings);
86    if add_source_files {
87        let sources = vinput
88            .input
89            .sources
90            .par_iter()
91            .filter_map(|(path, source)| {
92                pcx.sess.source_map().new_source_file(path.clone(), source.content.as_str()).ok()
93            })
94            .collect::<Vec<_>>();
95        pcx.add_files(sources);
96    }
97}
98
99fn configure_pcx_from_solc_cli(
100    pcx: &mut ParsingContext<'_>,
101    project: &Project,
102    cli_settings: &foundry_compilers::solc::CliSettings,
103) {
104    pcx.file_resolver
105        .set_current_dir(cli_settings.base_path.as_ref().unwrap_or(&project.paths.root));
106    for remapping in &project.paths.remappings {
107        pcx.file_resolver.add_import_remapping(solar::sema::interface::config::ImportRemapping {
108            context: remapping.context.clone().unwrap_or_default(),
109            prefix: remapping.name.clone(),
110            path: remapping.path.clone(),
111        });
112    }
113    pcx.file_resolver.add_include_paths(cli_settings.include_paths.iter().cloned());
114}