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)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xSwapFeeder authored and 0xmemorygrinder committed Feb 23, 2024
1 parent bf4d9fc commit 95b81cb
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 63 deletions.
36 changes: 13 additions & 23 deletions libs/solc-references/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod utils;
use error::ReferencesError;
use node_finder::NodeVisitor;
use solc_wrapper::{get_ast_for_file, SolcAstFile};
pub use solc_wrapper::SolcFile;
pub use solc_ast_rs_types::types::*;
pub use types::{Location, Position};
use types::{get_id, get_range, get_reference_id, InteractableNode};
Expand All @@ -17,28 +18,17 @@ use utils::index_to_position;

#[derive(Debug)]
pub struct ReferencesProvider {
pub files: Vec<SolcAstFile>
pub files: Vec<SolcAstFile>,
pub base_path: String
}

impl ReferencesProvider {
pub fn update_file_content(&mut self, filepath: String, content: String) -> Result<(), ReferencesError> {
let ast_files = get_ast_for_file(filepath, content)?;
for res_file in &ast_files {
let mut found = false;
for file in &mut self.files {
if file.ast.id == res_file.ast.id {
found = true;
file.ast = res_file.ast.clone();
if res_file.src.len() > 0 {
file.src = res_file.src.clone();
}
break;
}
}
if found == false {
self.files.push(res_file.clone());
}
}
pub fn set_base_path(&mut self, base_path: String) {
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)?;
Ok(())
}

Expand All @@ -47,7 +37,7 @@ impl ReferencesProvider {
let mut found_node: Option<InteractableNode> = None;
let mut node_finder = NodeVisitor::new(position.clone(), String::from(""));
for file in &self.files {
if let Some(node) = node_finder.find(&file.ast, &file.src) {
if let Some(node) = node_finder.find(&file.ast, &file.file.content) {
found_node = Some(node.clone());
eprintln!("Found node: {:?}", node);
break;
Expand All @@ -71,12 +61,12 @@ impl ReferencesProvider {
let nodes = usages_finder.find(&file.ast);
for node in nodes {
let range = get_range(&node);
let start = index_to_position(range.index, &file.src);
let end = index_to_position(range.index + range.length, &file.src);
let start = index_to_position(range.index, &file.file.content);
let end = index_to_position(range.index + range.length, &file.file.content);
let location = Location {
start,
end,
uri: file.file.clone()
uri: file.file.path.clone()
};
references.push(location);
}
Expand Down
59 changes: 37 additions & 22 deletions libs/solc-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,64 @@
mod solc;
mod error;

use std::ops::Index;

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

#[derive(Debug)]

#[derive(Debug, Clone)]
pub struct SolcFile {
pub path: String,
pub content: String,
}

#[derive(Debug, Clone)]
pub struct SolcJsonFile {
pub json: serde_json::Value,
pub file: String,
}
#[derive(Debug, Clone)]
pub struct SolcAstFile {
pub file: String,
pub ast: SourceUnit,
pub src: String,
pub file: SolcFile,
}


pub fn get_ast_for_file(filepath: String, content: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {

pub fn get_ast_for_file(base_path: String, files: Vec<SolcFile>) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
let solc = command::SolcCommand::new("solc");
let solc = solc.args(["--ast-compact-json", &filepath]);

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>>());
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, content, filepath)
}
get_ast_from_solc_output(&out, files)
}

pub fn get_ast_from_solc_output(output: &str, content: String, filepath: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
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)?;
let mut ast_files = Vec::new();
for file in files {
let ast: SourceUnit = serde_json::from_value(file.json)?;
if filepath.contains(&file.file.to_string()) {
ast_files.push(SolcAstFile {
file: file.file,
ast,
src: content.clone(),
});
}
else {
ast_files.push(SolcAstFile {
file: file.file,
ast,
src: String::new(),
});
let ast: SourceUnit = serde_json::from_value(file.clone().json).map_err(|e| {
eprintln!("Error parsing json: {}", file.clone().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;
}
}
}
Ok(ast_files)
Expand Down
1 change: 1 addition & 0 deletions toolchains/solidity/core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ exclude.workspace = true
tokio = { version = "1.36.0", features = ["full"] }
tower-lsp = "0.20.0"
solc-references = { path = "../../../../../libs/solc-references" }
glob = "0.3.1"
68 changes: 50 additions & 18 deletions toolchains/solidity/core/crates/references-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ struct Backend {

impl Backend {
pub fn new(client: Client) -> Self {
Self { client, references_provider: Arc::new(Mutex::new(ReferencesProvider { files: Vec::new() })) }
Self { client, references_provider: Arc::new(Mutex::new(ReferencesProvider { files: Vec::new(), base_path: String::new()})) }
}
}

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
if let Some(workspace) = params.workspace_folders {
self.references_provider.lock().await.set_base_path(normalize_path(workspace[0].uri.path()));
} else {
self.references_provider.lock().await.set_base_path(normalize_path(&params.root_uri.unwrap().path()));
}
Ok(InitializeResult {
server_info: None,
capabilities: ServerCapabilities {
Expand All @@ -53,25 +58,18 @@ impl LanguageServer for Backend {
self.client
.log_message(MessageType::INFO, "osmium-solidity-references initialized!")
.await;
}

async fn did_open(&self, params: DidOpenTextDocumentParams) {
if let Err(e) = self.references_provider.lock().await.update_file_content(normalize_path(params.text_document.uri.path()), params.text_document.text) {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).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;
}
}
}

async fn did_save(&self, params: DidSaveTextDocumentParams) {
let path = normalize_path(params.text_document.uri.path());
let content = match std::fs::read_to_string(&path) {
Ok(content) => content,
Err(e) => {
self.client.log_message(MessageType::ERROR, e).await;
return;
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(path, content) {
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
}
}

Expand Down Expand Up @@ -119,7 +117,41 @@ impl LanguageServer for Backend {
}

impl Backend {

pub async fn get_solc_files(&self) -> std::result::Result<Vec<SolcFile>, ()> {
// get all solidity files in the workspace directory + the following glob "*.sol"
let workspaces = self.client.workspace_folders().await.unwrap().unwrap();
let workspace = workspaces[0].uri.path();

let paths = match glob::glob(&format!("{}/**/*.sol", normalize_path(&workspace))) {
Ok(paths) => paths,
Err(e) => {
self.client.log_message(MessageType::ERROR, format!("Error reading file: {}", e)).await;
return Err(());
}
};
let mut files = vec![];
for path in paths.flatten() {
// check if is directory
let path = path.to_str().unwrap().to_string().replace("\\", "/").replace("c:/", "c://");
if std::fs::metadata(&path).unwrap().is_dir() || path.contains("forge-std") || path.contains("ds-test") {
continue;
}
files.push(path);
}

// read and store all file contents in a Vec<String>
Ok(
files.iter().map(|file| {
match std::fs::read_to_string(file) {
Ok(content) => Some(SolcFile {path: file.clone(), content}),
Err(e) => {
eprintln!("Error reading file '{}': {}, ", file, e);
None
}
}
}).filter(|x| x.is_some()).map(|x| x.unwrap()).collect()
)
}
}

#[tokio::main]
Expand Down

0 comments on commit 95b81cb

Please sign in to comment.