From be8e4391b66781249a3c8dff680c64fa71d9c7e0 Mon Sep 17 00:00:00 2001 From: Astrodevs CI Date: Wed, 4 Oct 2023 02:37:56 +0000 Subject: [PATCH 1/2] chore: create branch chore/70-references-rust-crate-from-ast/160-list-solidity-definitions-locations-staging --- remove-me-d2685428bf1f4b1e8cac.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 remove-me-d2685428bf1f4b1e8cac.txt diff --git a/remove-me-d2685428bf1f4b1e8cac.txt b/remove-me-d2685428bf1f4b1e8cac.txt new file mode 100644 index 00000000..34629223 --- /dev/null +++ b/remove-me-d2685428bf1f4b1e8cac.txt @@ -0,0 +1 @@ +d2685428bf1f4b1e8cac From a2e88daccbdd242fbbb982dad55c60e1a83a0fba Mon Sep 17 00:00:00 2001 From: 0xSwapFeeder Date: Wed, 4 Oct 2023 00:48:56 -0400 Subject: [PATCH 2/2] WIP --- libs/ast-extractor/src/lib.rs | 1 + libs/ast-extractor/src/retriever.rs | 3 +- libs/ast-extractor/src/retriever/finder.rs | 69 ++++++++++----- .../tests/files/contracts/two.sol | 3 +- libs/ast-references/.idea/.gitignore | 8 ++ libs/ast-references/.idea/ast-references.iml | 12 +++ libs/ast-references/.idea/modules.xml | 8 ++ libs/ast-references/.idea/vcs.xml | 6 ++ libs/ast-references/Cargo.lock | 1 + libs/ast-references/Cargo.toml | 3 +- libs/ast-references/src/definition_finder.rs | 55 ++++++++++++ libs/ast-references/src/file_retriever.rs | 88 +++++++++---------- libs/ast-references/src/lib.rs | 1 + .../src/types/contract_reference.rs | 6 ++ libs/ast-references/tests/contracts/test.sol | 9 ++ 15 files changed, 205 insertions(+), 68 deletions(-) create mode 100644 libs/ast-references/.idea/.gitignore create mode 100644 libs/ast-references/.idea/ast-references.iml create mode 100644 libs/ast-references/.idea/modules.xml create mode 100644 libs/ast-references/.idea/vcs.xml create mode 100644 libs/ast-references/src/definition_finder.rs create mode 100644 libs/ast-references/tests/contracts/test.sol diff --git a/libs/ast-extractor/src/lib.rs b/libs/ast-extractor/src/lib.rs index 00c15349..e5fb2598 100644 --- a/libs/ast-extractor/src/lib.rs +++ b/libs/ast-extractor/src/lib.rs @@ -2,6 +2,7 @@ pub mod errors; pub mod extract; pub mod retriever; + // Expose syn_solidity crate pub use syn_solidity::*; diff --git a/libs/ast-extractor/src/retriever.rs b/libs/ast-extractor/src/retriever.rs index 7cea2262..d3cd7c01 100644 --- a/libs/ast-extractor/src/retriever.rs +++ b/libs/ast-extractor/src/retriever.rs @@ -20,7 +20,8 @@ mod udt; pub use udt::*; mod using; -mod finder; +pub mod finder; +pub use finder::*; pub use using::*; diff --git a/libs/ast-extractor/src/retriever/finder.rs b/libs/ast-extractor/src/retriever/finder.rs index f7150a9d..d0b823a9 100644 --- a/libs/ast-extractor/src/retriever/finder.rs +++ b/libs/ast-extractor/src/retriever/finder.rs @@ -98,6 +98,14 @@ impl<'ast> Visit<'ast> for FinderVisitor { } } + fn visit_stmt_var_decl(&mut self, stmt_var_decl: &'ast StmtVarDecl) { + if is_in_range!(stmt_var_decl.span().start(), stmt_var_decl.span().end(), self.to_find) { + println!("stmt: {:?}", stmt_var_decl); + visit::visit_stmt_var_decl(self, stmt_var_decl); + } + } + + fn visit_expr(&mut self, expr: &'ast Expr) { if is_in_range!(expr.span().start(), expr.span().end(), self.to_find) { println!("expr: {:?}", expr); @@ -106,7 +114,6 @@ impl<'ast> Visit<'ast> for FinderVisitor { } } - fn visit_expr_call(&mut self, call: &'ast ExprCall) { if is_in_range!(call.span().start(), call.span().end(), self.to_find) { if !is_in_range!(call.args.span().start(), call.args.span().end(), self.to_find) { @@ -124,9 +131,18 @@ impl<'ast> Visit<'ast> for FinderVisitor { } } + fn visit_ident(&mut self, ident: &'ast SolIdent) { + if self.found.is_some() { + return; + } + if is_in_range!(ident.span().start(), ident.span().end(), self.to_find) { + self.found = Some(FoundNode::IdentUsageName(self.current_contract.clone(), self.current_function.clone(), self.current_expr.clone(), ident.clone())); + } + } + fn visit_type(&mut self, ty: &'ast Type) { - println!("type: {:?}", ty); if is_in_range!(ty.span().start(), ty.span().end(), self.to_find) { + println!("type: {:?}", ty); self.found = Some(FoundNode::TypeUsage(self.current_contract.clone(), self.current_function.clone(), self.current_expr.clone(), ty.clone())); visit::visit_type(self, ty); } @@ -146,12 +162,6 @@ impl<'ast> Visit<'ast> for FinderVisitor { } - fn visit_stmt_var_decl(&mut self, stmt_var_decl: &'ast StmtVarDecl) { - if is_in_range!(stmt_var_decl.span().start(), stmt_var_decl.span().end(), self.to_find) { - visit::visit_stmt_var_decl(self, stmt_var_decl); - } - } - fn visit_variable_definition(&mut self, var: &'ast VariableDefinition) { if is_in_range!(var.span().start(), var.span().end(), self.to_find) { self.current_property = Some(var.clone()); @@ -168,6 +178,7 @@ impl<'ast> Visit<'ast> for FinderVisitor { } fn visit_item_contract(&mut self, contract: &'ast ItemContract) { + println!("contract: {:?}", contract); let _contract_start = contract.brace_token.span().start(); let _contract_end = contract.brace_token.span().end(); self.current_contract = Some(contract.clone()); @@ -231,6 +242,7 @@ impl<'ast> Visit<'ast> for FinderVisitor { } fn visit_item_function(&mut self, function: &'ast ItemFunction) { + println!("function: {:?}", function); self.current_function = Some(function.clone()); if is_in_range!(function.name.span().start(), function.name.span().end(), self.to_find) { self.found = Some(FoundNode::FunctionDefName(self.current_contract.clone().unwrap(), function.clone())); @@ -245,24 +257,18 @@ impl<'ast> Visit<'ast> for FinderVisitor { } } } + if let Some(ret) = function.return_type() { + visit::visit_type(self, &ret); + } if let FunctionBody::Block(block) = &function.body { + let _block_start = block.span().start(); + let _block_end = block.span().end(); if is_in_range!(block.span().start(), block.span().end(), self.to_find) { visit::visit_item_function(self, function); } } - if let Some(ret) = function.return_type() { - visit::visit_type(self, &ret); - } - self.current_function = None; - } - fn visit_ident(&mut self, ident: &'ast SolIdent) { - if self.found.is_some() { - return; - } - if is_in_range!(ident.span().start(), ident.span().end(), self.to_find) { - self.found = Some(FoundNode::IdentUsageName(self.current_contract.clone(), self.current_function.clone(), self.current_expr.clone(), ident.clone())); - } + self.current_function = None; } fn visit_item_struct(&mut self, strukt: &'ast ItemStruct) { @@ -900,7 +906,7 @@ mod tests { let tokens = TokenStream::from_str(source.as_str()).unwrap(); let ast = parse2(tokens).unwrap(); - let res = retrieve_node_from_position(&ast, Position::new(5, 14)); + let res = retrieve_node_from_position(&ast, Position::new(16, 36)); if let Some(FoundNode::IdentUsageName(_contract, _func, _expr, ident)) = res { assert_eq!(ident.to_string(), "storedData"); @@ -949,4 +955,25 @@ mod tests { } } + #[test] + fn test_retrieve_const_usage() { + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("tests"); + path.push("files"); + path.push("contracts"); + path.push("two.sol"); + let source = fs::read_to_string(path).unwrap(); + + let tokens = TokenStream::from_str(source.as_str()).unwrap(); + let ast = parse2(tokens).unwrap(); + let res = retrieve_node_from_position(&ast, Position::new(16, 29)); + println!("{:?}", res); + + if let Some(FoundNode::IdentUsageName(_contract, _func, _expr, ident)) = res { + assert_eq!(ident.to_string(), "x"); + } else { + panic!() + } + } + } diff --git a/libs/ast-extractor/tests/files/contracts/two.sol b/libs/ast-extractor/tests/files/contracts/two.sol index 31a22d93..b9cacf4b 100644 --- a/libs/ast-extractor/tests/files/contracts/two.sol +++ b/libs/ast-extractor/tests/files/contracts/two.sol @@ -8,11 +8,12 @@ abstract contract One { function get() public view returns (uint) { return storedData; } + uint8 constant myConst = 1; } abstract contract Two { - uint storedData; function set(uint x) public { + uint storedData = One.myConst; storedData = x; } diff --git a/libs/ast-references/.idea/.gitignore b/libs/ast-references/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/libs/ast-references/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/libs/ast-references/.idea/ast-references.iml b/libs/ast-references/.idea/ast-references.iml new file mode 100644 index 00000000..bbe0a70f --- /dev/null +++ b/libs/ast-references/.idea/ast-references.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/ast-references/.idea/modules.xml b/libs/ast-references/.idea/modules.xml new file mode 100644 index 00000000..e3e65061 --- /dev/null +++ b/libs/ast-references/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/libs/ast-references/.idea/vcs.xml b/libs/ast-references/.idea/vcs.xml new file mode 100644 index 00000000..b2bdec2d --- /dev/null +++ b/libs/ast-references/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/libs/ast-references/Cargo.lock b/libs/ast-references/Cargo.lock index b156f712..7cca3a7d 100644 --- a/libs/ast-references/Cargo.lock +++ b/libs/ast-references/Cargo.lock @@ -19,6 +19,7 @@ version = "0.1.0" dependencies = [ "ast-extractor", "proc-macro2", + "thiserror", ] [[package]] diff --git a/libs/ast-references/Cargo.toml b/libs/ast-references/Cargo.toml index cef452db..6a75370e 100644 --- a/libs/ast-references/Cargo.toml +++ b/libs/ast-references/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] proc-macro2 = { version = "1.0.66", features = ["span-locations"]} -ast-extractor = { path = "../ast-extractor"} \ No newline at end of file +ast-extractor = { path = "../ast-extractor"} +thiserror = "1.0.48" \ No newline at end of file diff --git a/libs/ast-references/src/definition_finder.rs b/libs/ast-references/src/definition_finder.rs new file mode 100644 index 00000000..3111a389 --- /dev/null +++ b/libs/ast-references/src/definition_finder.rs @@ -0,0 +1,55 @@ +use std::fmt::Error; +use ast_extractor::retriever::{Position, retrieve_node_from_position}; +use ast_extractor::retriever::finder::{FoundNode}; +use ast_extractor::{ItemContract, ItemFunction, ItemStruct, Type, Visit, visit}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum RetrieveDefinitionError { + Extract(#[from] ast_extractor::extract::ExtractError) +} + +pub struct DefinitionFinder { + pos: Position, + definitions: Vec +} + +impl <'ast>Visit <'ast> for DefinitionFinder { + fn visit_item_contract(&mut self, contract: &'ast ItemContract) { + if is_in_range!(self.pos, contract) { + visit::visit_item_contract(self, contract); + } + } + + + + fn visit_item_struct(&mut self, strukt: &'ast ItemStruct) { + + } + +} + + +fn retreive_definition_from_pos(file: &str, files: Vec<&str>, pos: Position) -> Result { + let fileAst = ast_extractor::extract::extract_ast_from_content(file)?; + let res = retrieve_node_from_position(&fileAst, pos); + + if let Some(node) = res { + match &node { + FoundNode::TypeUsage(_, _, _, Type::Custom(t)) => { + Ok(node) + } + FoundNode::IdentUsageCall(_, _, _) => { + + } + FoundNode::IdentUsageName(_, _, _, _) => {} + _ => {Ok(node)} + } + } else { + } +} + + + + +uint256 myNewVariable = MyContract.constVar; \ No newline at end of file diff --git a/libs/ast-references/src/file_retriever.rs b/libs/ast-references/src/file_retriever.rs index 7efabdb1..b27d8c15 100644 --- a/libs/ast-references/src/file_retriever.rs +++ b/libs/ast-references/src/file_retriever.rs @@ -69,6 +69,37 @@ impl<'ast> Visit<'ast> for FileVisitor { ast_extractor::visit::visit_variable_definition(self, i) } + fn visit_item_contract(&mut self, i: &ItemContract) { + let contract_reference = ContractReference::new( + i.name.to_string(), + Location::new( + self.file_reference.borrow_mut().path.clone(), + Bound::new( + i.name.span().start().line as u32, + i.name.span().start().column as u32, + ), + Bound::new( + i.name.span().end().line as u32, + i.name.span().end().column as u32, + ), + ), + &self.file_reference, + ); + self.file_reference + .borrow_mut() + .add_contract(contract_reference); + self.current_contract = Some( + self.file_reference + .borrow() + .contracts + .last() + .unwrap() + .clone(), + ); + ast_extractor::visit::visit_item_contract(self, i); + self.current_contract = None; + } + fn visit_item_enum(&mut self, i: &'ast ItemEnum) { let enum_reference = EnumReference::new( i.name.to_string(), @@ -98,8 +129,8 @@ impl<'ast> Visit<'ast> for FileVisitor { ast_extractor::visit::visit_item_enum(self, i) } - fn visit_item_contract(&mut self, i: &ItemContract) { - let contract_reference = ContractReference::new( + fn visit_item_error(&mut self, i: &'ast ItemError) { + let error_reference = ErrorReference::new( i.name.to_string(), Location::new( self.file_reference.borrow_mut().path.clone(), @@ -112,21 +143,19 @@ impl<'ast> Visit<'ast> for FileVisitor { i.name.span().end().column as u32, ), ), - &self.file_reference, + self.current_contract.as_ref(), + Some(&self.file_reference), ); - self.file_reference - .borrow_mut() - .add_contract(contract_reference); - self.current_contract = Some( - self.file_reference - .borrow() - .contracts - .last() + if self.current_contract.is_some() { + self.current_contract + .as_ref() .unwrap() - .clone(), - ); - ast_extractor::visit::visit_item_contract(self, i); - self.current_contract = None; + .borrow_mut() + .add_error(&Rc::new(RefCell::new(error_reference))); + } else { + self.file_reference.borrow_mut().add_error(error_reference); + } + ast_extractor::visit::visit_item_error(self, i) } fn visit_item_event(&mut self, i: &'ast ItemEvent) { @@ -215,35 +244,6 @@ impl<'ast> Visit<'ast> for FileVisitor { } ast_extractor::visit::visit_item_struct(self, i) } - - fn visit_item_error(&mut self, i: &'ast ItemError) { - let error_reference = ErrorReference::new( - i.name.to_string(), - Location::new( - self.file_reference.borrow_mut().path.clone(), - Bound::new( - i.name.span().start().line as u32, - i.name.span().start().column as u32, - ), - Bound::new( - i.name.span().end().line as u32, - i.name.span().end().column as u32, - ), - ), - self.current_contract.as_ref(), - Some(&self.file_reference), - ); - if self.current_contract.is_some() { - self.current_contract - .as_ref() - .unwrap() - .borrow_mut() - .add_error(&Rc::new(RefCell::new(error_reference))); - } else { - self.file_reference.borrow_mut().add_error(error_reference); - } - ast_extractor::visit::visit_item_error(self, i) - } } pub fn retrieve_file_reference_from_path(path: String) -> Rc> { diff --git a/libs/ast-references/src/lib.rs b/libs/ast-references/src/lib.rs index 03782f9a..0a351d4e 100644 --- a/libs/ast-references/src/lib.rs +++ b/libs/ast-references/src/lib.rs @@ -1,2 +1,3 @@ pub mod file_retriever; pub mod types; +mod definition_finder; diff --git a/libs/ast-references/src/types/contract_reference.rs b/libs/ast-references/src/types/contract_reference.rs index 819a66a4..0b05aa1a 100644 --- a/libs/ast-references/src/types/contract_reference.rs +++ b/libs/ast-references/src/types/contract_reference.rs @@ -23,11 +23,14 @@ use super::event_reference::EventReference; pub struct ContractReference { pub name: String, + pub is_library: bool, pub location: Location, pub file: Rc>, pub structs: Vec>>, pub functions: Vec>>, pub properties: Vec>>, + pub variables: Vec>>, + pub constants: Vec>>, pub errors: Vec>>, pub events: Vec>>, pub enums: Vec>>, @@ -42,10 +45,13 @@ impl ContractReference { name: String, location: Location, file: &Rc>, + is_library: bool, ) -> ContractReference { ContractReference { name: name, + is_library: is_library, location: location, + file: file.clone(), structs: Vec::new(), functions: Vec::new(), diff --git a/libs/ast-references/tests/contracts/test.sol b/libs/ast-references/tests/contracts/test.sol new file mode 100644 index 00000000..ff8b19b3 --- /dev/null +++ b/libs/ast-references/tests/contracts/test.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.8.0; + +contract Good { + function f() public pure returns (uint) { + string myString; + myString; + return 1; + } +}