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

Commit c780698

Browse files
committed
wip(solidity/references)
1 parent e88e818 commit c780698

File tree

5 files changed

+102
-63
lines changed

5 files changed

+102
-63
lines changed

libs/solc-references/src/lib.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod utils;
99
use error::ReferencesError;
1010
use node_finder::NodeVisitor;
1111
use solc_wrapper::{get_ast_for_file, SolcAstFile};
12+
pub use solc_wrapper::SolcFile;
1213
pub use solc_ast_rs_types::types::*;
1314
pub use types::{Location, Position};
1415
use types::{get_id, get_range, get_reference_id, InteractableNode};
@@ -17,28 +18,17 @@ use utils::index_to_position;
1718

1819
#[derive(Debug)]
1920
pub struct ReferencesProvider {
20-
pub files: Vec<SolcAstFile>
21+
pub files: Vec<SolcAstFile>,
22+
pub base_path: String
2123
}
2224

2325
impl ReferencesProvider {
24-
pub fn update_file_content(&mut self, filepath: String, content: String) -> Result<(), ReferencesError> {
25-
let ast_files = get_ast_for_file(filepath, content)?;
26-
for res_file in &ast_files {
27-
let mut found = false;
28-
for file in &mut self.files {
29-
if file.ast.id == res_file.ast.id {
30-
found = true;
31-
file.ast = res_file.ast.clone();
32-
if res_file.src.len() > 0 {
33-
file.src = res_file.src.clone();
34-
}
35-
break;
36-
}
37-
}
38-
if found == false {
39-
self.files.push(res_file.clone());
40-
}
41-
}
26+
pub fn set_base_path(&mut self, base_path: String) {
27+
self.base_path = base_path;
28+
}
29+
30+
pub fn update_file_content(&mut self, files: Vec<SolcFile>) -> Result<(), ReferencesError> {
31+
self.files = get_ast_for_file(self.base_path.clone(), files)?;
4232
Ok(())
4333
}
4434

@@ -47,7 +37,7 @@ impl ReferencesProvider {
4737
let mut found_node: Option<InteractableNode> = None;
4838
let mut node_finder = NodeVisitor::new(position.clone(), String::from(""));
4939
for file in &self.files {
50-
if let Some(node) = node_finder.find(&file.ast, &file.src) {
40+
if let Some(node) = node_finder.find(&file.ast, &file.file.content) {
5141
found_node = Some(node.clone());
5242
eprintln!("Found node: {:?}", node);
5343
break;
@@ -71,12 +61,12 @@ impl ReferencesProvider {
7161
let nodes = usages_finder.find(&file.ast);
7262
for node in nodes {
7363
let range = get_range(&node);
74-
let start = index_to_position(range.index, &file.src);
75-
let end = index_to_position(range.index + range.length, &file.src);
64+
let start = index_to_position(range.index, &file.file.content);
65+
let end = index_to_position(range.index + range.length, &file.file.content);
7666
let location = Location {
7767
start,
7868
end,
79-
uri: file.file.clone()
69+
uri: file.file.path.clone()
8070
};
8171
references.push(location);
8272
}

libs/solc-wrapper/src/lib.rs

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,64 @@
11
mod solc;
22
mod error;
33

4+
use std::ops::Index;
5+
46
pub use error::SolcWrapperError;
57
use solc::*;
68
use solc_ast_rs_types::types::SourceUnit;
79

8-
#[derive(Debug)]
10+
11+
#[derive(Debug, Clone)]
12+
pub struct SolcFile {
13+
pub path: String,
14+
pub content: String,
15+
}
16+
17+
#[derive(Debug, Clone)]
918
pub struct SolcJsonFile {
1019
pub json: serde_json::Value,
1120
pub file: String,
1221
}
1322
#[derive(Debug, Clone)]
1423
pub struct SolcAstFile {
15-
pub file: String,
1624
pub ast: SourceUnit,
17-
pub src: String,
25+
pub file: SolcFile,
1826
}
1927

2028

21-
pub fn get_ast_for_file(filepath: String, content: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
29+
30+
pub fn get_ast_for_file(base_path: String, files: Vec<SolcFile>) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
2231
let solc = command::SolcCommand::new("solc");
23-
let solc = solc.args(["--ast-compact-json", &filepath]);
32+
33+
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/")];
34+
args.extend(files.iter().map(|file| file.path.clone()).collect::<Vec<String>>());
35+
let solc = solc.args(args);
2436
let out = solc.execute()?;
37+
if !out.status.success() {
38+
let stderr = String::from_utf8_lossy(&out.stderr);
39+
eprintln!("Error running solc: {}", stderr);
40+
}
2541
let out = String::from_utf8_lossy(&out.stdout);
26-
get_ast_from_solc_output(&out, content, filepath)
27-
}
42+
get_ast_from_solc_output(&out, files)
43+
}
2844

29-
pub fn get_ast_from_solc_output(output: &str, content: String, filepath: String) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
45+
pub fn get_ast_from_solc_output(output: &str, input_files: Vec<SolcFile>) -> Result<Vec<SolcAstFile>, SolcWrapperError> {
3046
let files = get_files_from_solc_output(output)?;
3147
let mut ast_files = Vec::new();
3248
for file in files {
33-
let ast: SourceUnit = serde_json::from_value(file.json)?;
34-
if filepath.contains(&file.file.to_string()) {
35-
ast_files.push(SolcAstFile {
36-
file: file.file,
37-
ast,
38-
src: content.clone(),
39-
});
40-
}
41-
else {
42-
ast_files.push(SolcAstFile {
43-
file: file.file,
44-
ast,
45-
src: String::new(),
46-
});
49+
let ast: SourceUnit = serde_json::from_value(file.clone().json).map_err(|e| {
50+
eprintln!("Error parsing json: {}", file.clone().json);
51+
e
52+
})?;
53+
let out_path = &file.file;
54+
for input_file in &input_files{
55+
if input_file.path.contains(out_path) {
56+
ast_files.push(SolcAstFile {
57+
file: input_file.clone(),
58+
ast,
59+
});
60+
break;
61+
}
4762
}
4863
}
4964
Ok(ast_files)

toolchains/solidity/core/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

toolchains/solidity/core/crates/references-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ exclude.workspace = true
1212
tokio = { version = "1.36.0", features = ["full"] }
1313
tower-lsp = "0.20.0"
1414
solc-references = { path = "../../../../../libs/solc-references" }
15+
glob = "0.3.1"

toolchains/solidity/core/crates/references-server/src/main.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@ struct Backend {
2020

2121
impl Backend {
2222
pub fn new(client: Client) -> Self {
23-
Self { client, references_provider: Arc::new(Mutex::new(ReferencesProvider { files: Vec::new() })) }
23+
Self { client, references_provider: Arc::new(Mutex::new(ReferencesProvider { files: Vec::new(), base_path: String::new()})) }
2424
}
2525
}
2626

2727
#[tower_lsp::async_trait]
2828
impl LanguageServer for Backend {
29-
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
29+
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
30+
if let Some(workspace) = params.workspace_folders {
31+
self.references_provider.lock().await.set_base_path(normalize_path(workspace[0].uri.path()));
32+
} else {
33+
self.references_provider.lock().await.set_base_path(normalize_path(&params.root_uri.unwrap().path()));
34+
}
3035
Ok(InitializeResult {
3136
server_info: None,
3237
capabilities: ServerCapabilities {
@@ -53,25 +58,18 @@ impl LanguageServer for Backend {
5358
self.client
5459
.log_message(MessageType::INFO, "osmium-solidity-references initialized!")
5560
.await;
56-
}
57-
58-
async fn did_open(&self, params: DidOpenTextDocumentParams) {
59-
if let Err(e) = self.references_provider.lock().await.update_file_content(normalize_path(params.text_document.uri.path()), params.text_document.text) {
60-
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
61+
if let Ok(input_files) = self.get_solc_files().await {
62+
if let Err(e) = self.references_provider.lock().await.update_file_content(input_files) {
63+
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
64+
}
6165
}
6266
}
6367

64-
async fn did_save(&self, params: DidSaveTextDocumentParams) {
65-
let path = normalize_path(params.text_document.uri.path());
66-
let content = match std::fs::read_to_string(&path) {
67-
Ok(content) => content,
68-
Err(e) => {
69-
self.client.log_message(MessageType::ERROR, e).await;
70-
return;
68+
async fn did_save(&self, _: DidSaveTextDocumentParams) {
69+
if let Ok(input_files) = self.get_solc_files().await {
70+
if let Err(e) = self.references_provider.lock().await.update_file_content(input_files) {
71+
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
7172
}
72-
};
73-
if let Err(e) = self.references_provider.lock().await.update_file_content(path, content) {
74-
self.client.log_message(MessageType::ERROR, format!("Error updating file content: {}", e)).await;
7573
}
7674
}
7775

@@ -119,7 +117,41 @@ impl LanguageServer for Backend {
119117
}
120118

121119
impl Backend {
122-
120+
pub async fn get_solc_files(&self) -> std::result::Result<Vec<SolcFile>, ()> {
121+
// get all solidity files in the workspace directory + the following glob "*.sol"
122+
let workspaces = self.client.workspace_folders().await.unwrap().unwrap();
123+
let workspace = workspaces[0].uri.path();
124+
125+
let paths = match glob::glob(&format!("{}/**/*.sol", normalize_path(&workspace))) {
126+
Ok(paths) => paths,
127+
Err(e) => {
128+
self.client.log_message(MessageType::ERROR, format!("Error reading file: {}", e)).await;
129+
return Err(());
130+
}
131+
};
132+
let mut files = vec![];
133+
for path in paths.flatten() {
134+
// check if is directory
135+
let path = path.to_str().unwrap().to_string().replace("\\", "/").replace("c:/", "c://");
136+
if std::fs::metadata(&path).unwrap().is_dir() || path.contains("forge-std") || path.contains("ds-test") {
137+
continue;
138+
}
139+
files.push(path);
140+
}
141+
142+
// read and store all file contents in a Vec<String>
143+
Ok(
144+
files.iter().map(|file| {
145+
match std::fs::read_to_string(file) {
146+
Ok(content) => Some(SolcFile {path: file.clone(), content}),
147+
Err(e) => {
148+
eprintln!("Error reading file '{}': {}, ", file, e);
149+
None
150+
}
151+
}
152+
}).filter(|x| x.is_some()).map(|x| x.unwrap()).collect()
153+
)
154+
}
123155
}
124156

125157
#[tokio::main]

0 commit comments

Comments
 (0)