Browse Source

Add import mapping to match solc's mapping functionality

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 4 năm trước cách đây
mục cha
commit
6a8a5f0c15

+ 5 - 0
docs/running.rst

@@ -51,6 +51,11 @@ Options:
   will only search the current directory. This option can be specified multiple times
   and the directories will be searched in the order specified.
 
+\\-\\-importmap *map=directory*
+  When resolving ``import`` directives, if the first part of the path matches *map*,
+  search the directory provided for the file. This option can be specified multiple times
+  with different values for map.
+
 \\-\\-help, -h
   This displays a short description of all the options
 

+ 4 - 6
src/bin/languageserver/mod.rs

@@ -9,7 +9,7 @@ use tower_lsp::{Client, LanguageServer};
 use tower_lsp::{LspService, Server};
 
 use solang::codegen::codegen;
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::parse_and_resolve;
 use solang::parser::pt;
 use solang::sema::{ast, builtin::get_prototype, symtable, tags::render};
@@ -49,17 +49,15 @@ impl SolangServer {
     /// Parse file
     async fn parse_file(&self, uri: Url) {
         if let Ok(path) = uri.to_file_path() {
-            let mut filecache = FileCache::new();
+            let mut resolver = FileResolver::new();
 
             let dir = path.parent().unwrap();
 
-            if let Ok(dir) = dir.canonicalize() {
-                filecache.add_import_path(dir);
-            }
+            let _ = resolver.add_import_path(PathBuf::from(dir));
 
             let os_str = path.file_name().unwrap();
 
-            let mut ns = parse_and_resolve(os_str.to_str().unwrap(), &mut filecache, self.target);
+            let mut ns = parse_and_resolve(os_str.to_str().unwrap(), &mut resolver, self.target);
 
             // codegen all the contracts; some additional errors/warnings will be detected here
             codegen(&mut ns, &Default::default());

+ 41 - 23
src/bin/solang.rs

@@ -2,6 +2,7 @@ use clap::{App, Arg, ArgMatches};
 use itertools::Itertools;
 use serde::Serialize;
 use std::collections::HashMap;
+use std::ffi::OsString;
 use std::fs::File;
 use std::io::prelude::*;
 use std::path::{Path, PathBuf};
@@ -9,7 +10,7 @@ use std::path::{Path, PathBuf};
 use solang::abi;
 use solang::codegen::{codegen, Options};
 use solang::emit::Generate;
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::sema::{ast::Namespace, diagnostics};
 
 mod doc;
@@ -91,7 +92,17 @@ fn main() {
                 .short("I")
                 .long("importpath")
                 .takes_value(true)
-                .multiple(true),
+                .multiple(true)
+                .require_delimiter(true),
+        )
+        .arg(
+            Arg::with_name("IMPORTMAP")
+                .help("Map directory to search for solidity files [format: map=path]")
+                .short("m")
+                .long("importmap")
+                .takes_value(true)
+                .multiple(true)
+                .require_delimiter(true),
         )
         .arg(
             Arg::with_name("CONSTANTFOLDING")
@@ -161,34 +172,41 @@ fn main() {
 
     let math_overflow_check = matches.is_present("MATHOVERFLOW");
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     for filename in matches.values_of("INPUT").unwrap() {
         if let Ok(path) = PathBuf::from(filename).canonicalize() {
-            cache.add_import_path(path.parent().unwrap().to_path_buf());
+            let _ = cache.add_import_path(path.parent().unwrap().to_path_buf());
         }
     }
 
-    match PathBuf::from(".").canonicalize() {
-        Ok(p) => cache.add_import_path(p),
-        Err(e) => {
-            eprintln!(
-                "error: cannot add current directory to import path: {}",
-                e.to_string()
-            );
-            std::process::exit(1);
-        }
+    if let Err(e) = cache.add_import_path(PathBuf::from(".")) {
+        eprintln!(
+            "error: cannot add current directory to import path: {}",
+            e.to_string()
+        );
+        std::process::exit(1);
     }
 
     if let Some(paths) = matches.values_of("IMPORTPATH") {
-        for p in paths {
-            let path = PathBuf::from(p);
-            match path.canonicalize() {
-                Ok(p) => cache.add_import_path(p),
-                Err(e) => {
-                    eprintln!("error: import path ‘{}’: {}", p, e.to_string());
+        for path in paths {
+            if let Err(e) = cache.add_import_path(PathBuf::from(path)) {
+                eprintln!("error: import path ‘{}’: {}", path, e.to_string());
+                std::process::exit(1);
+            }
+        }
+    }
+
+    if let Some(maps) = matches.values_of("IMPORTMAP") {
+        for p in maps {
+            if let Some((map, path)) = p.split_once('=') {
+                if let Err(e) = cache.add_import_map(OsString::from(map), PathBuf::from(path)) {
+                    eprintln!("error: import path ‘{}’: {}", path, e.to_string());
                     std::process::exit(1);
                 }
+            } else {
+                eprintln!("error: import map ‘{}’: contains no ‘=’", p);
+                std::process::exit(1);
             }
         }
     }
@@ -356,7 +374,7 @@ fn output_file(matches: &ArgMatches, stem: &str, ext: &str) -> PathBuf {
 
 fn process_filename(
     filename: &str,
-    cache: &mut FileCache,
+    resolver: &mut FileResolver,
     target: solang::Target,
     matches: &ArgMatches,
     json: &mut JsonResult,
@@ -367,16 +385,16 @@ fn process_filename(
     let mut json_contracts = HashMap::new();
 
     // resolve phase
-    let mut ns = solang::parse_and_resolve(filename, cache, target);
+    let mut ns = solang::parse_and_resolve(filename, resolver, target);
 
     // codegen all the contracts; some additional errors/warnings will be detected here
     codegen(&mut ns, opt);
 
     if matches.is_present("STD-JSON") {
-        let mut out = diagnostics::message_as_json(&ns, cache);
+        let mut out = diagnostics::message_as_json(&ns, resolver);
         json.errors.append(&mut out);
     } else {
-        diagnostics::print_messages(cache, &ns, verbose);
+        diagnostics::print_messages(resolver, &ns, verbose);
     }
 
     if ns.contracts.is_empty() || diagnostics::any_errors(&ns.diagnostics) {

+ 91 - 39
src/file_cache.rs → src/file_resolver.rs

@@ -1,14 +1,16 @@
 use crate::parser::pt::Loc;
 use crate::sema::ast;
 use std::collections::HashMap;
+use std::ffi::OsString;
 use std::fs::File;
-use std::io::prelude::*;
+use std::io;
+use std::io::{prelude::*, Error, ErrorKind};
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
-pub struct FileCache {
+pub struct FileResolver {
     /// Set of import paths search for imports
-    import_paths: Vec<PathBuf>,
+    import_paths: Vec<(Option<OsString>, PathBuf)>,
     /// List file by import path
     cached_paths: HashMap<PathBuf, usize>,
     /// The actual file contents
@@ -31,25 +33,43 @@ pub struct ResolvedFile {
     base: PathBuf,
 }
 
-impl Default for FileCache {
+impl Default for FileResolver {
     fn default() -> Self {
-        FileCache::new()
+        FileResolver::new()
     }
 }
 
-impl FileCache {
+impl FileResolver {
     /// Create a new file cache object
     pub fn new() -> Self {
-        FileCache {
+        FileResolver {
             import_paths: Vec::new(),
             cached_paths: HashMap::new(),
             files: Vec::new(),
         }
     }
 
-    /// Add import path. This must be the canonicalized path
-    pub fn add_import_path(&mut self, path: PathBuf) {
-        self.import_paths.push(path);
+    /// Add import path
+    pub fn add_import_path(&mut self, path: PathBuf) -> io::Result<()> {
+        self.import_paths.push((None, path.canonicalize()?));
+        Ok(())
+    }
+
+    /// Add import map
+    pub fn add_import_map(&mut self, map: OsString, path: PathBuf) -> io::Result<()> {
+        if self
+            .import_paths
+            .iter()
+            .any(|(m, _)| m.as_ref() == Some(&map))
+        {
+            Err(Error::new(
+                ErrorKind::Other,
+                format!("duplicate mapping for ‘{}’", map.to_string_lossy()),
+            ))
+        } else {
+            self.import_paths.push((Some(map), path.canonicalize()?));
+            Ok(())
+        }
     }
 
     /// Update the cache for the filename with the given contents
@@ -114,6 +134,35 @@ impl FileCache {
         filename: &str,
     ) -> Result<ResolvedFile, String> {
         let path = PathBuf::from(filename);
+
+        // first check maps
+        let mut iter = path.iter();
+        if let Some(first_part) = iter.next() {
+            let relpath: PathBuf = iter.collect();
+
+            for (import_no, import) in self.import_paths.iter().enumerate() {
+                if let (Some(mapping), import_path) = import {
+                    if first_part == mapping {
+                        // match!
+                        if let Ok(full_path) = import_path.join(&relpath).canonicalize() {
+                            let file_no = self.load_file(&full_path)?;
+                            let base = full_path
+                                .parent()
+                                .expect("path should include filename")
+                                .to_path_buf();
+
+                            return Ok(ResolvedFile {
+                                full_path,
+                                base,
+                                import_no,
+                                file_no,
+                            });
+                        }
+                    }
+                }
+            }
+        }
+
         let mut start_import_no = 0;
 
         // first try relative to the parent
@@ -138,21 +187,23 @@ impl FileCache {
                 });
             }
 
-            let import_path = self.import_paths[*import_no].join(base);
-
-            if let Ok(full_path) = import_path.join(path.clone()).canonicalize() {
-                let file_no = self.load_file(&full_path)?;
-                let base = full_path
-                    .parent()
-                    .expect("path should include filename")
-                    .to_path_buf();
-
-                return Ok(ResolvedFile {
-                    full_path,
-                    base,
-                    import_no: *import_no,
-                    file_no,
-                });
+            if let (None, import_path) = &self.import_paths[*import_no] {
+                let import_path = import_path.join(base);
+
+                if let Ok(full_path) = import_path.join(path.clone()).canonicalize() {
+                    let file_no = self.load_file(&full_path)?;
+                    let base = full_path
+                        .parent()
+                        .expect("path should include filename")
+                        .to_path_buf();
+
+                    return Ok(ResolvedFile {
+                        full_path,
+                        base,
+                        import_no: *import_no,
+                        file_no,
+                    });
+                }
             }
 
             // start with the next import
@@ -178,21 +229,22 @@ impl FileCache {
         // walk over the import paths until we find one that resolves
         for i in 0..self.import_paths.len() {
             let import_no = (i + start_import_no) % self.import_paths.len();
-            let import_path = &self.import_paths[import_no];
-
-            if let Ok(full_path) = import_path.join(path.clone()).canonicalize() {
-                let base = full_path
-                    .parent()
-                    .expect("path should include filename")
-                    .to_path_buf();
-                let file_no = self.load_file(&full_path)?;
 
-                return Ok(ResolvedFile {
-                    full_path,
-                    file_no,
-                    import_no,
-                    base,
-                });
+            if let (None, import_path) = &self.import_paths[import_no] {
+                if let Ok(full_path) = import_path.join(path.clone()).canonicalize() {
+                    let base = full_path
+                        .parent()
+                        .expect("path should include filename")
+                        .to_path_buf();
+                    let file_no = self.load_file(&full_path)?;
+
+                    return Ok(ResolvedFile {
+                        full_path,
+                        file_no,
+                        import_no,
+                        base,
+                    });
+                }
             }
         }
 

+ 11 - 7
src/lib.rs

@@ -1,7 +1,7 @@
 pub mod abi;
 pub mod codegen;
 pub mod emit;
-pub mod file_cache;
+pub mod file_resolver;
 pub mod linker;
 pub mod parser;
 
@@ -11,7 +11,7 @@ pub mod parser;
 #[allow(clippy::result_unit_err)]
 pub mod sema;
 
-use file_cache::FileCache;
+use file_resolver::FileResolver;
 use inkwell::OptimizationLevel;
 use sema::ast;
 use sema::diagnostics;
@@ -53,12 +53,12 @@ impl fmt::Display for Target {
 /// The ctx is the inkwell llvm context.
 pub fn compile(
     filename: &str,
-    cache: &mut FileCache,
+    resolver: &mut FileResolver,
     opt_level: OptimizationLevel,
     target: Target,
     math_overflow_check: bool,
 ) -> (Vec<(Vec<u8>, String)>, ast::Namespace) {
-    let mut ns = parse_and_resolve(filename, cache, target);
+    let mut ns = parse_and_resolve(filename, resolver, target);
 
     if diagnostics::any_errors(&ns.diagnostics) {
         return (Vec::new(), ns);
@@ -106,7 +106,11 @@ pub fn compile_many<'a>(
 /// informational messages like `found contact N`.
 ///
 /// Note that multiple contracts can be specified in on solidity source file.
-pub fn parse_and_resolve(filename: &str, cache: &mut FileCache, target: Target) -> ast::Namespace {
+pub fn parse_and_resolve(
+    filename: &str,
+    resolver: &mut FileResolver,
+    target: Target,
+) -> ast::Namespace {
     let mut ns = ast::Namespace::new(
         target,
         match target {
@@ -123,7 +127,7 @@ pub fn parse_and_resolve(filename: &str, cache: &mut FileCache, target: Target)
         },
     );
 
-    match cache.resolve_file(None, filename) {
+    match resolver.resolve_file(None, filename) {
         Err(message) => {
             ns.diagnostics.push(ast::Diagnostic {
                 ty: ast::ErrorType::ParserError,
@@ -134,7 +138,7 @@ pub fn parse_and_resolve(filename: &str, cache: &mut FileCache, target: Target)
             });
         }
         Ok(file) => {
-            sema::sema(&file, cache, &mut ns);
+            sema::sema(&file, resolver, &mut ns);
         }
     }
 

+ 1 - 1
src/sema/ast.rs

@@ -370,7 +370,7 @@ pub struct File {
     pub path: PathBuf,
     /// Used for offset to line-column conversions
     pub line_starts: Vec<usize>,
-    /// Indicates the file number in FileCache.files
+    /// Indicates the file number in FileResolver.files
     pub cache_no: usize,
 }
 

+ 4 - 4
src/sema/diagnostics.rs

@@ -1,5 +1,5 @@
 use super::ast::{Diagnostic, ErrorType, Level, Namespace, Note};
-use crate::file_cache::FileCache;
+use crate::file_resolver::FileResolver;
 use crate::parser::pt::Loc;
 use serde::Serialize;
 
@@ -131,7 +131,7 @@ impl Diagnostic {
         }
     }
 
-    fn formatted_message(&self, ns: &Namespace, cache: &FileCache) -> String {
+    fn formatted_message(&self, ns: &Namespace, cache: &FileResolver) -> String {
         let mut s = if let Some(pos) = self.pos {
             let loc = ns.files[pos.0].loc_to_string(&pos);
 
@@ -178,7 +178,7 @@ impl Diagnostic {
     }
 }
 
-pub fn print_messages(cache: &FileCache, ns: &Namespace, debug: bool) {
+pub fn print_messages(cache: &FileResolver, ns: &Namespace, debug: bool) {
     for msg in &ns.diagnostics {
         if !debug && msg.level == Level::Debug {
             continue;
@@ -212,7 +212,7 @@ pub struct OutputJson {
     pub formattedMessage: String,
 }
 
-pub fn message_as_json(ns: &Namespace, cache: &FileCache) -> Vec<OutputJson> {
+pub fn message_as_json(ns: &Namespace, cache: &FileResolver) -> Vec<OutputJson> {
     let mut json = Vec::new();
 
     for msg in &ns.diagnostics {

+ 9 - 9
src/sema/mod.rs

@@ -31,7 +31,7 @@ use self::expression::expression;
 use self::functions::{resolve_params, resolve_returns};
 use self::symtable::Symtable;
 use self::variables::var_decl;
-use crate::file_cache::{FileCache, ResolvedFile};
+use crate::file_resolver::{FileResolver, ResolvedFile};
 use crate::sema::unused_variable::{check_unused_events, check_unused_namespace_variables};
 
 pub type ArrayDimension = Option<(pt::Loc, BigInt)>;
@@ -42,8 +42,8 @@ pub const SOLANA_SPARSE_ARRAY_SIZE: u64 = 1024;
 
 /// Load a file file from the cache, parse and resolve it. The file must be present in
 /// the cache.
-pub fn sema(file: &ResolvedFile, cache: &mut FileCache, ns: &mut ast::Namespace) {
-    sema_file(file, cache, ns);
+pub fn sema(file: &ResolvedFile, resolver: &mut FileResolver, ns: &mut ast::Namespace) {
+    sema_file(file, resolver, ns);
 
     // Checks for unused variables
     check_unused_namespace_variables(ns);
@@ -51,10 +51,10 @@ pub fn sema(file: &ResolvedFile, cache: &mut FileCache, ns: &mut ast::Namespace)
 }
 
 /// Parse and resolve a file and its imports in a recursive manner.
-fn sema_file(file: &ResolvedFile, cache: &mut FileCache, ns: &mut ast::Namespace) {
+fn sema_file(file: &ResolvedFile, resolver: &mut FileResolver, ns: &mut ast::Namespace) {
     let file_no = ns.files.len();
 
-    let (source_code, file_cache_no) = cache.get_file_contents_and_number(&file.full_path);
+    let (source_code, file_cache_no) = resolver.get_file_contents_and_number(&file.full_path);
 
     ns.files.push(ast::File::new(
         file.full_path.clone(),
@@ -96,7 +96,7 @@ fn sema_file(file: &ResolvedFile, cache: &mut FileCache, ns: &mut ast::Namespace
                 resolve_pragma(name, value, ns);
             }
             pt::SourceUnitPart::ImportDirective(import) => {
-                resolve_import(import, Some(file), file_no, cache, ns);
+                resolve_import(import, Some(file), file_no, resolver, ns);
             }
             _ => (),
         }
@@ -164,7 +164,7 @@ fn resolve_import(
     import: &pt::Import,
     parent: Option<&ResolvedFile>,
     file_no: usize,
-    cache: &mut FileCache,
+    resolver: &mut FileResolver,
     ns: &mut ast::Namespace,
 ) {
     let filename = match import {
@@ -173,7 +173,7 @@ fn resolve_import(
         pt::Import::Rename(f, _) => f,
     };
 
-    let import_file_no = match cache.resolve_file(parent, &filename.string) {
+    let import_file_no = match resolver.resolve_file(parent, &filename.string) {
         Err(message) => {
             ns.diagnostics
                 .push(ast::Diagnostic::error(filename.loc, message));
@@ -182,7 +182,7 @@ fn resolve_import(
         }
         Ok(file) => {
             if !ns.files.iter().any(|f| f.path == file.full_path) {
-                sema_file(&file, cache, ns);
+                sema_file(&file, resolver, ns);
 
                 // give up if we failed
                 if diagnostics::any_errors(&ns.diagnostics) {

+ 3 - 3
tests/ewasm.rs

@@ -10,7 +10,7 @@ use tiny_keccak::{Hasher, Keccak};
 use wasmi::memory_units::Pages;
 use wasmi::*;
 
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::sema::{ast, diagnostics};
 use solang::{compile, Target};
 
@@ -794,7 +794,7 @@ impl TestRuntime {
 }
 
 fn build_solidity(src: &str) -> TestRuntime {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 
@@ -852,7 +852,7 @@ fn simple_solidiy_compile_and_run() {
 }
 
 pub fn parse_and_resolve(src: &'static str, target: Target) -> ast::Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 

+ 94 - 0
tests/imports.rs

@@ -0,0 +1,94 @@
+use assert_cmd::Command;
+
+#[test]
+fn import_map_dup() {
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let dup = cmd
+        .args(&[
+            "--importmap",
+            "foo=tests",
+            "--importmap",
+            "foo=tests",
+            "foo.sol",
+        ])
+        .env("exit", "1")
+        .assert();
+
+    let output = dup.get_output();
+    let stderr = String::from_utf8_lossy(&output.stderr);
+
+    println!("stderr: {}", stderr);
+
+    assert_eq!(
+        stderr,
+        "error: import path ‘tests’: duplicate mapping for ‘foo’\n"
+    );
+}
+
+#[test]
+fn import_map_badpath() {
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let badpath = cmd
+        .args(&["--importmap", "foo=/does/not/exist", "bar.sol"])
+        .env("exit", "1")
+        .assert();
+
+    let output = badpath.get_output();
+    let stderr = String::from_utf8_lossy(&output.stderr);
+
+    println!("stderr: {}", stderr);
+
+    assert!(stderr.contains("error: import path ‘/does/not/exist’: "));
+}
+
+#[test]
+fn import_map() {
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let assert = cmd
+        .args(&["--importmap", "foo=imports/", "import_map.sol"])
+        .current_dir("tests/imports_testcases")
+        .assert();
+
+    let output = assert.get_output();
+
+    assert_eq!(String::from_utf8_lossy(&output.stderr), "");
+
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let badpath = cmd
+        .args(&["import_map.sol"])
+        .current_dir("tests/imports_testcases")
+        .assert();
+
+    let output = badpath.get_output();
+    let stderr = String::from_utf8_lossy(&output.stderr);
+
+    println!("stderr: {}", stderr);
+
+    assert!(stderr.contains("import_map.sol:1:8-21: error: file not found ‘foo/bar.sol’"));
+}
+
+#[test]
+fn import() {
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let assert = cmd
+        .args(&["--importpath", "imports", "import.sol"])
+        .current_dir("tests/imports_testcases")
+        .assert();
+
+    let output = assert.get_output();
+
+    assert_eq!(String::from_utf8_lossy(&output.stderr), "");
+
+    let mut cmd = Command::cargo_bin("solang").unwrap();
+    let badpath = cmd
+        .args(&["import.sol"])
+        .current_dir("tests/imports_testcases")
+        .assert();
+
+    let output = badpath.get_output();
+    let stderr = String::from_utf8_lossy(&output.stderr);
+
+    println!("stderr: {}", stderr);
+
+    assert!(stderr.contains("error: file not found ‘bar.sol’"));
+}

+ 1 - 0
tests/imports_testcases/import.sol

@@ -0,0 +1 @@
+import "bar.sol";

+ 1 - 0
tests/imports_testcases/import_map.sol

@@ -0,0 +1 @@
+import "foo/bar.sol";

+ 1 - 0
tests/imports_testcases/imports/bar.sol

@@ -0,0 +1 @@
+contract c {}

+ 3 - 3
tests/solana.rs

@@ -22,7 +22,7 @@ use solang::{
     codegen::{codegen, Options},
     compile_many,
     emit::Generate,
-    file_cache::FileCache,
+    file_resolver::FileResolver,
     sema::{ast, diagnostics},
     Target,
 };
@@ -110,7 +110,7 @@ struct Assign {
 }
 
 fn build_solidity(src: &str) -> VirtualMachine {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 
@@ -1522,7 +1522,7 @@ impl VirtualMachine {
 }
 
 pub fn parse_and_resolve(src: &'static str, target: Target) -> ast::Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 

+ 4 - 4
tests/substrate.rs

@@ -10,7 +10,7 @@ use wasmi::memory_units::Pages;
 use wasmi::*;
 
 use solang::abi;
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::sema::ast;
 use solang::sema::diagnostics;
 use solang::{compile, Target};
@@ -1181,7 +1181,7 @@ impl TestRuntime {
 }
 
 pub fn parse_and_resolve(src: &'static str, target: Target) -> ast::Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 
@@ -1189,7 +1189,7 @@ pub fn parse_and_resolve(src: &'static str, target: Target) -> ast::Namespace {
 }
 
 pub fn build_solidity(src: &'static str) -> TestRuntime {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 
@@ -1226,7 +1226,7 @@ pub fn build_solidity(src: &'static str) -> TestRuntime {
 }
 
 pub fn build_solidity_with_overflow_check(src: &'static str) -> TestRuntime {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents("test.sol", src.to_string());
 

+ 5 - 5
tests/substrate_tests/events.rs

@@ -1,7 +1,7 @@
 use crate::{build_solidity, first_error, first_warning, no_errors, parse_and_resolve};
 use parity_scale_codec::Encode;
 use parity_scale_codec_derive::{Decode, Encode};
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::Target;
 
 #[test]
@@ -315,7 +315,7 @@ fn emit() {
 
 #[test]
 fn event_imported() {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -343,7 +343,7 @@ fn event_imported() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -373,7 +373,7 @@ fn event_imported() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -403,7 +403,7 @@ fn event_imported() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",

+ 21 - 21
tests/substrate_tests/imports.rs

@@ -1,10 +1,10 @@
 use crate::{first_error, no_errors};
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::Target;
 
 #[test]
 fn enum_import() {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -30,7 +30,7 @@ fn enum_import() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -56,7 +56,7 @@ fn enum_import() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -82,7 +82,7 @@ fn enum_import() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -108,7 +108,7 @@ fn enum_import() {
     );
 
     // from has special handling to avoid making it a keyword
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -125,7 +125,7 @@ fn enum_import() {
         "‘frum’ found where ‘from’ expected"
     );
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -145,7 +145,7 @@ fn enum_import() {
 
 #[test]
 fn struct_import() {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -171,7 +171,7 @@ fn struct_import() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -200,7 +200,7 @@ fn struct_import() {
 
 #[test]
 fn contract_import() {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -235,7 +235,7 @@ fn contract_import() {
     no_errors(ns.diagnostics);
 
     // lets try a importing an import
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -278,7 +278,7 @@ fn contract_import() {
     no_errors(ns.diagnostics);
 
     // now let's rename an import in a chain
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -323,7 +323,7 @@ fn contract_import() {
 
 #[test]
 fn circular_import() {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "self.sol",
@@ -343,7 +343,7 @@ fn circular_import() {
 
     no_errors(ns.diagnostics);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -388,7 +388,7 @@ fn circular_import() {
 #[test]
 fn import_symbol() {
     // import struct via import symbol
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -419,7 +419,7 @@ fn import_symbol() {
     no_errors(ns.diagnostics);
 
     // import contract via import symbol
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -454,7 +454,7 @@ fn import_symbol() {
     no_errors(ns.diagnostics);
 
     // import enum in contract via import symbol
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -489,7 +489,7 @@ fn import_symbol() {
     no_errors(ns.diagnostics);
 
     // import struct in contract via import symbol chain
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -537,7 +537,7 @@ fn import_symbol() {
 #[test]
 fn enum_import_chain() {
     // import struct in contract via import symbol chain
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -584,7 +584,7 @@ fn enum_import_chain() {
     no_errors(ns.diagnostics);
 
     // now with error
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -637,7 +637,7 @@ fn enum_import_chain() {
 #[test]
 fn import_base_dir() {
     // if a imports x/b.sol then when x/b.sol imports, it should use x/ as a base
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",

+ 3 - 3
tests/substrate_tests/inheritance.rs

@@ -1,7 +1,7 @@
 use crate::{build_solidity, first_error, first_warning, no_errors, parse_and_resolve};
 use parity_scale_codec::Encode;
 use parity_scale_codec_derive::{Decode, Encode};
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::Target;
 
 #[test]
@@ -94,7 +94,7 @@ fn test_abstract() {
         "cannot construct ‘foo’ of type ‘abstract contract’"
     );
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",
@@ -128,7 +128,7 @@ fn test_abstract() {
 
     assert_eq!(contracts.len(), 1);
 
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
 
     cache.set_file_contents(
         "a.sol",

+ 2 - 2
tests/undefined_variable_detection.rs

@@ -1,11 +1,11 @@
 use solang::codegen::{codegen, Options};
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::sema::ast::Diagnostic;
 use solang::sema::ast::{Level, Namespace};
 use solang::{parse_and_resolve, Target};
 
 fn parse_and_codegen(src: &'static str) -> Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
     cache.set_file_contents("test.sol", src.to_string());
     let mut ns = parse_and_resolve("test.sol", &mut cache, Target::Generic);
 

+ 3 - 3
tests/unused_variable_detection.rs

@@ -1,18 +1,18 @@
 use itertools::Itertools;
-use solang::file_cache::FileCache;
+use solang::file_resolver::FileResolver;
 use solang::sema::ast;
 use solang::sema::ast::{Diagnostic, Level};
 use solang::{parse_and_resolve, Target};
 
 fn generic_target_parse(src: &'static str) -> ast::Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
     cache.set_file_contents("test.sol", src.to_string());
 
     parse_and_resolve("test.sol", &mut cache, Target::Generic)
 }
 
 fn generic_parse_two_files(src1: &'static str, src2: &'static str) -> ast::Namespace {
-    let mut cache = FileCache::new();
+    let mut cache = FileResolver::new();
     cache.set_file_contents("test.sol", src1.to_string());
     cache.set_file_contents("test2.sol", src2.to_string());