fix(solc): invalidate cache on unresolve error (#1337)
This commit is contained in:
parent
214d24dfd2
commit
030488eca5
|
@ -781,12 +781,17 @@ pub(crate) enum ArtifactsCache<'a, T: ArtifactOutput> {
|
||||||
|
|
||||||
impl<'a, T: ArtifactOutput> ArtifactsCache<'a, T> {
|
impl<'a, T: ArtifactOutput> ArtifactsCache<'a, T> {
|
||||||
pub fn new(project: &'a Project<T>, edges: GraphEdges) -> Result<Self> {
|
pub fn new(project: &'a Project<T>, edges: GraphEdges) -> Result<Self> {
|
||||||
/// returns the [SolFilesCache] to use
|
/// Returns the [SolFilesCache] to use
|
||||||
fn get_cache<T: ArtifactOutput>(project: &Project<T>) -> SolFilesCache {
|
///
|
||||||
|
/// Returns a new empty cache if the cache does not exist or `invalidate_cache` is set.
|
||||||
|
fn get_cache<T: ArtifactOutput>(
|
||||||
|
project: &Project<T>,
|
||||||
|
invalidate_cache: bool,
|
||||||
|
) -> SolFilesCache {
|
||||||
// the currently configured paths
|
// the currently configured paths
|
||||||
let paths = project.paths.paths_relative();
|
let paths = project.paths.paths_relative();
|
||||||
|
|
||||||
if project.cache_path().exists() {
|
if !invalidate_cache && project.cache_path().exists() {
|
||||||
if let Ok(cache) = SolFilesCache::read_joined(&project.paths) {
|
if let Ok(cache) = SolFilesCache::read_joined(&project.paths) {
|
||||||
if cache.paths == paths {
|
if cache.paths == paths {
|
||||||
// unchanged project paths
|
// unchanged project paths
|
||||||
|
@ -794,13 +799,19 @@ impl<'a, T: ArtifactOutput> ArtifactsCache<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// new empty cache
|
// new empty cache
|
||||||
SolFilesCache::new(Default::default(), paths)
|
SolFilesCache::new(Default::default(), paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
let cache = if project.cached {
|
let cache = if project.cached {
|
||||||
|
// we only read the existing cache if we were able to resolve the entire graph
|
||||||
|
// if we failed to resolve an import we invalidate the cache so don't get any false
|
||||||
|
// positives
|
||||||
|
let invalidate_cache = !edges.unresolved_imports().is_empty();
|
||||||
|
|
||||||
// read the cache file if it already exists
|
// read the cache file if it already exists
|
||||||
let mut cache = get_cache(project);
|
let mut cache = get_cache(project, invalidate_cache);
|
||||||
|
|
||||||
cache.remove_missing_files();
|
cache.remove_missing_files();
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,8 @@ pub struct GraphEdges {
|
||||||
/// Combined with the `indices` this way we can determine if a file was original added to the
|
/// Combined with the `indices` this way we can determine if a file was original added to the
|
||||||
/// graph as input or was added as resolved import, see [`Self::is_input_file()`]
|
/// graph as input or was added as resolved import, see [`Self::is_input_file()`]
|
||||||
num_input_files: usize,
|
num_input_files: usize,
|
||||||
|
/// tracks all imports that we failed to resolve
|
||||||
|
unresolved_imports: HashSet<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphEdges {
|
impl GraphEdges {
|
||||||
|
@ -111,6 +113,11 @@ impl GraphEdges {
|
||||||
self.files().skip(self.num_input_files)
|
self.files().skip(self.num_input_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all imports that we failed to resolve
|
||||||
|
pub fn unresolved_imports(&self) -> &HashSet<PathBuf> {
|
||||||
|
&self.unresolved_imports
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a list of nodes the given node index points to for the given kind.
|
/// Returns a list of nodes the given node index points to for the given kind.
|
||||||
pub fn imported_nodes(&self, from: usize) -> &[usize] {
|
pub fn imported_nodes(&self, from: usize) -> &[usize] {
|
||||||
&self.edges[from]
|
&self.edges[from]
|
||||||
|
@ -277,6 +284,7 @@ impl Graph {
|
||||||
self.nodes.iter().take(self.edges.num_input_files)
|
self.nodes.iter().take(self.edges.num_input_files)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all files imported by the given file
|
||||||
pub fn imports(&self, path: impl AsRef<Path>) -> HashSet<&PathBuf> {
|
pub fn imports(&self, path: impl AsRef<Path>) -> HashSet<&PathBuf> {
|
||||||
self.edges.imports(path)
|
self.edges.imports(path)
|
||||||
}
|
}
|
||||||
|
@ -327,7 +335,7 @@ impl Graph {
|
||||||
|
|
||||||
// keep track of all unique paths that we failed to resolve to not spam the reporter with
|
// keep track of all unique paths that we failed to resolve to not spam the reporter with
|
||||||
// the same path
|
// the same path
|
||||||
let mut unresolved_paths = HashSet::new();
|
let mut unresolved_imports = HashSet::new();
|
||||||
|
|
||||||
// now we need to resolve all imports for the source file and those imported from other
|
// now we need to resolve all imports for the source file and those imported from other
|
||||||
// locations
|
// locations
|
||||||
|
@ -346,7 +354,7 @@ impl Graph {
|
||||||
add_node(&mut unresolved, &mut index, &mut resolved_imports, import)?;
|
add_node(&mut unresolved, &mut index, &mut resolved_imports, import)?;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if unresolved_paths.insert(import_path.to_path_buf()) {
|
if unresolved_imports.insert(import_path.to_path_buf()) {
|
||||||
crate::report::unresolved_import(import_path, &paths.remappings);
|
crate::report::unresolved_import(import_path, &paths.remappings);
|
||||||
}
|
}
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
|
@ -372,6 +380,7 @@ impl Graph {
|
||||||
.map(|(idx, node)| (idx, node.data.version_req.clone()))
|
.map(|(idx, node)| (idx, node.data.version_req.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
|
unresolved_imports,
|
||||||
};
|
};
|
||||||
Ok(Graph { nodes, edges, root: paths.root.clone() })
|
Ok(Graph { nodes, edges, root: paths.root.clone() })
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
io,
|
fs, io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
@ -1768,3 +1768,46 @@ contract D { }
|
||||||
cache.files.keys().cloned().collect::<Vec<_>>()
|
cache.files.keys().cloned().collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_failure_after_removing_file() {
|
||||||
|
let project = TempProject::dapptools().unwrap();
|
||||||
|
project
|
||||||
|
.add_source(
|
||||||
|
"A",
|
||||||
|
r#"
|
||||||
|
pragma solidity ^0.8.10;
|
||||||
|
import "./B.sol";
|
||||||
|
contract A { }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
project
|
||||||
|
.add_source(
|
||||||
|
"B",
|
||||||
|
r#"
|
||||||
|
pragma solidity ^0.8.10;
|
||||||
|
import "./C.sol";
|
||||||
|
contract B { }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let c = project
|
||||||
|
.add_source(
|
||||||
|
"C",
|
||||||
|
r#"
|
||||||
|
pragma solidity ^0.8.10;
|
||||||
|
contract C { }
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let compiled = project.compile().unwrap();
|
||||||
|
assert!(!compiled.has_compiler_errors());
|
||||||
|
|
||||||
|
fs::remove_file(c).unwrap();
|
||||||
|
let compiled = project.compile().unwrap();
|
||||||
|
assert!(compiled.has_compiler_errors());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue