Skip to content
This repository has been archived by the owner on Jul 3, 2024. It is now read-only.

Commit

Permalink
wip(solidity/references): changed to foundry compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
0xSwapFeeder committed Feb 25, 2024
1 parent 95b81cb commit 42bbb4c
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 145 deletions.
4 changes: 2 additions & 2 deletions libs/solc-references/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ impl ReferencesProvider {
self.base_path = base_path;
}

pub fn update_file_content(&mut self, files: Vec<SolcFile>) -> Result<(), ReferencesError> {
self.files = get_ast_for_file(self.base_path.clone(), files)?;
pub fn update_file_content(&mut self) -> Result<(), ReferencesError> {
self.files = get_ast_for_file(self.base_path.clone())?;
Ok(())
}

Expand Down
10 changes: 8 additions & 2 deletions libs/solc-wrapper/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use thiserror::Error;

use crate::solc::error::CommandError;
use crate::forge::error::CommandError;

#[derive(Error, Debug)]
pub enum SolcWrapperError {
#[error("Solc error: {0}")]
Solc(#[from] CommandError),
#[error("JSON parsing error: {0}")]
Json(#[from] serde_json::Error)
Json(#[from] serde_json::Error),
#[error("No build info produced by foundry")]
NoBuildInfo,
#[error("Cannot read build info file")]
ReadBuildInfo(#[from] std::io::Error),
#[error("Cannot read source file")]
ReadSourceFile(std::io::Error)
}
62 changes: 62 additions & 0 deletions libs/solc-wrapper/src/forge/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::process::Command;
use std::process::Stdio;
use std::path::PathBuf;

use super::error::{CommandError, CommandType};

pub struct ForgeCommand {
args: Vec<String>,
bin_path : PathBuf,
current_dir: String
}

impl Default for ForgeCommand {
fn default() -> Self {
ForgeCommand::new("forge")
}
}

impl ForgeCommand {

pub fn new(path: impl Into<PathBuf>) -> Self {
ForgeCommand {
args: Vec::new(),
bin_path: path.into(),
current_dir: String::from(".")
}
}

pub fn current_dir(mut self, current_dir: String) -> Self {
self.current_dir = current_dir;
self
}

pub fn arg<T: Into<String>>(mut self, arg: T) -> Self {
self.args.push(arg.into());
self
}

pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
for arg in args {
self = self.arg(arg);
}
self
}

pub fn execute(&self) -> Result<(), CommandError> {
Command::new(&self.bin_path)
.current_dir(&self.current_dir)
.args(&self.args)
.stdout(Stdio::piped())
.output()
.map_err(|e| {
eprintln!("Forge Command Error: {}", e.to_string());
CommandError { error: e.to_string(), command_type: CommandType::ParseFile }
})?;
Ok(())
}
}
File renamed without changes.
File renamed without changes.
87 changes: 25 additions & 62 deletions libs/solc-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
mod solc;
mod forge;
mod error;

use std::ops::Index;
mod output;

pub use error::SolcWrapperError;
use solc::*;
use forge::*;
use solc_ast_rs_types::types::SourceUnit;

use output::get_files_from_solc_output;

#[derive(Debug, Clone)]
pub struct SolcFile {
Expand All @@ -19,83 +18,47 @@ pub struct SolcJsonFile {
pub json: serde_json::Value,
pub file: String,
}

#[derive(Debug, Clone)]
pub struct SolcAstFile {
pub ast: SourceUnit,
pub file: SolcFile,
}


pub fn get_ast_for_file(base_path: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
let solc = command::ForgeCommand::default();

pub fn get_ast_for_file(base_path: String, files: Vec<SolcFile>) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
let solc = command::SolcCommand::new("solc");

let mut args = vec![String::from("--ast-compact-json"), String::from("--base-path"), base_path, String::from("ds-test/=lib/forge-std/lib/ds-test/src/"), String::from("forge-std/=lib/forge-std/src/")];
args.extend(files.iter().map(|file| file.path.clone()).collect::<Vec<String>>());
eprintln!("Base path: {}", base_path.clone());
let args = vec![String::from("build"), String::from("--build-info"), /*String::from("--no-cache")*/];
let solc = solc.args(args);
let out = solc.execute()?;
if !out.status.success() {
let stderr = String::from_utf8_lossy(&out.stderr);
eprintln!("Error running solc: {}", stderr);
}
let out = String::from_utf8_lossy(&out.stdout);
get_ast_from_solc_output(&out, files)
}
solc.current_dir(base_path.clone()).execute()?;
get_ast_from_solc_output(base_path)
}

pub fn get_ast_from_solc_output(output: &str, input_files: Vec<SolcFile>) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
let files = get_files_from_solc_output(output)?;
pub fn get_ast_from_solc_output(base_path: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
let files = get_files_from_solc_output(&base_path)?;
let mut ast_files = Vec::new();
for file in files {
let ast: SourceUnit = serde_json::from_value(file.clone().json).map_err(|e| {
eprintln!("Error parsing json: {}", file.clone().json);
eprintln!("Error while parsing json ast: {:?},\n json: {}", e, file.json);
e
})?;
let out_path = &file.file;
for input_file in &input_files{
if input_file.path.contains(out_path) {
ast_files.push(SolcAstFile {
file: input_file.clone(),
ast,
});
break;
}
}
ast_files.push(SolcAstFile {
file: SolcFile {
path: out_path.clone(),
content: std::fs::read_to_string(&out_path).map_err(|e| {
eprintln!("Error reading compiled file : {}", e);
SolcWrapperError::ReadSourceFile(e)
})?,
},
ast,
});
}
Ok(ast_files)
}

fn get_files_from_solc_output(output: &str) -> Result<Vec<SolcJsonFile>, SolcWrapperError> {
let mut files = Vec::new();
let mut current_json = String::new();
let mut current_file = String::new();

for line in output.lines() {
if !line.starts_with("=======") && current_file.len() == 0 && current_json.len() == 0 {
continue;
}
if line.starts_with("=======") {
if current_json.len() > 0 && current_file.len() > 0 {
let json: serde_json::Value = serde_json::from_str(&current_json)?;
files.push(SolcJsonFile {
json,
file: current_file
});
current_json = String::new();
}
current_file = line.trim_start_matches("======= ").trim_end_matches(" =======").to_string();
continue;
}
current_json.push_str(line);
}
let json: serde_json::Value = serde_json::from_str(&current_json)?;
files.push(SolcJsonFile {
json,
file: current_file
});
Ok(files)
}


#[cfg(test)]
mod tests {
use super::*;
Expand Down
45 changes: 45 additions & 0 deletions libs/solc-wrapper/src/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::io;
use std::path::PathBuf;
use std::fs::{read_dir, DirEntry};
use crate::SolcJsonFile;
use crate::error::SolcWrapperError;
use serde_json;

pub fn get_files_from_solc_output(base_path: &str) -> Result<Vec<SolcJsonFile>, SolcWrapperError> {
let mut files = Vec::new();

let output = std::fs::read_to_string(get_last_build_info(base_path)?)?;
let json: serde_json::Value = serde_json::from_str(&output)?;
for (file, json) in json["output"]["sources"].as_object().ok_or(SolcWrapperError::NoBuildInfo)? {
files.push(SolcJsonFile {
json: json["ast"].clone(),
file: file.clone()
});
};

Ok(files)
}

fn get_last_build_info(base_path: &str) -> Result<PathBuf, SolcWrapperError> {
let out = read_dir(base_path.to_string() + "/out/build-info")?;

let mut entries: Vec<DirEntry> = out.flatten().collect();
entries.sort_by(|a, b| {
sort_latest(a, b).unwrap_or(std::cmp::Ordering::Equal)
});
let last_build_info = entries.first().ok_or(SolcWrapperError::NoBuildInfo)?;
Ok(last_build_info.path())
}

fn sort_latest(a: &DirEntry, b: &DirEntry) -> Result<std::cmp::Ordering, io::Error> {
if let Ok(met_a) = a.metadata() {
if let Ok(met_b) = b.metadata() {
if met_a.created()? > met_b.created()? {
return Ok(std::cmp::Ordering::Greater);
} else {
return Ok(std::cmp::Ordering::Less);
}
}
}
Ok(std::cmp::Ordering::Equal)
}
69 changes: 0 additions & 69 deletions libs/solc-wrapper/src/solc/command.rs

This file was deleted.

12 changes: 4 additions & 8 deletions toolchains/solidity/core/crates/references-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,14 @@ impl LanguageServer for Backend {
self.client
.log_message(MessageType::INFO, "osmium-solidity-references initialized!")
.await;
if let Ok(input_files) = self.get_solc_files().await {
if let Err(e) = self.references_provider.lock().await.update_file_content(input_files) {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
}
if let Err(e) = self.references_provider.lock().await.update_file_content() {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
}
}

async fn did_save(&self, _: DidSaveTextDocumentParams) {
if let Ok(input_files) = self.get_solc_files().await {
if let Err(e) = self.references_provider.lock().await.update_file_content(input_files) {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
}
if let Err(e) = self.references_provider.lock().await.update_file_content() {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
}
}

Expand Down
4 changes: 2 additions & 2 deletions toolchains/solidity/extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ let testManager: TestManager;

export async function activate(context: ExtensionContext) {
linterClient = await createLinterClient(context);
foundryCompilerClient = createFoundryCompilerClient(context);
// foundryCompilerClient = createFoundryCompilerClient(context);
slitherClient = await createSlitherClient(context);
referencesClient = await createReferencesClient(context);
testsPositionsClient = await createTestsPositionsClient(context);
if (workspace.workspaceFolders?.length) {
testManager = new TestManager(testsPositionsClient, workspace.workspaceFolders[0].uri.fsPath);
}

context.subscriptions.push(linterClient, foundryCompilerClient, slitherClient, testsPositionsClient, testManager.testController, referencesClient);
context.subscriptions.push(linterClient, slitherClient, testsPositionsClient, testManager.testController, referencesClient);

registerForgeFmtLinter(context);
registerGasEstimation();
Expand Down

0 comments on commit 42bbb4c

Please sign in to comment.