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

Commit

Permalink
wip(solidty/references)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xSwapFeeder committed Feb 26, 2024
1 parent 42bbb4c commit 270fb24
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 84 deletions.
4 changes: 2 additions & 2 deletions libs/solc-references/Cargo.lock

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

2 changes: 1 addition & 1 deletion libs/solc-references/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
solc-ast-rs-types = { version = "0.1.2", features = ["visit"]}
solc-ast-rs-types = { version = "0.1.6", features = ["visit"]}
solc-wrapper = { path="../solc-wrapper" }
thiserror = "1.0.56"
19 changes: 11 additions & 8 deletions libs/solc-references/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use types::{get_id, get_range, get_reference_id, InteractableNode};
use usages::UsagesFinder;
use utils::index_to_position;

use crate::utils::is_node_a_type;

#[derive(Debug)]
pub struct ReferencesProvider {
pub files: Vec<SolcAstFile>,
Expand All @@ -32,16 +34,17 @@ impl ReferencesProvider {
Ok(())
}

pub fn get_references(&self, position: Position) -> Vec<Location> {
pub fn get_references(&self, uri: &str, position: Position) -> Vec<Location> {
let mut references: Vec<Location> = Vec::new();
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.file.content) {
found_node = Some(node.clone());
eprintln!("Found node: {:?}", node);
break;
}
if let Some(file) = self.files.iter().find(|file| file.file.path == uri) {
found_node = node_finder.find(&file.ast, &file.file.content);
eprintln!("Found node: {:?}", found_node);
}
else {
eprintln!("No file found at uri: {}", uri);
return references;
}
if found_node.is_none() {
eprintln!("No node found at position: {:?}", &position);
Expand All @@ -56,7 +59,7 @@ impl ReferencesProvider {

eprintln!("Ref id: {:?}", ref_id);

let mut usages_finder = UsagesFinder::new(ref_id);
let mut usages_finder = UsagesFinder::new(ref_id, is_node_a_type(&found_node));
for file in &self.files {
let nodes = usages_finder.find(&file.ast);
for node in nodes {
Expand Down
12 changes: 2 additions & 10 deletions libs/solc-references/src/node_finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,10 @@ impl <'ast> Visit<'ast> for NodeVisitor {
}

fn visit_identifier(&mut self, identifier: &'ast Identifier) {
if (identifier.name == "newNumber") {
let range = source_location_to_range(&identifier.src);
eprintln!("Visiting identifier: {:?}", identifier);
eprintln!("Requested Position: {:?}", self.position);
eprintln!("Requested Source: {:?}", self.source);
eprintln!("Requested Index: {:?}", position_to_index(&self.position, &self.source));
eprintln!("Ident Index: {:?}", range.index);
eprintln!("Ident len: {:?}", range.length);
}
if is_node_in_range(&identifier.src, &self.position, &self.source) {
eprintln!("Identifier in range: {:?}", identifier);
self.above_node = self.node.clone();
self.node = Some(InteractableNode::Identifier(identifier.clone(), Box::new(self.above_node.clone().unwrap())));
self.node = Some(InteractableNode::Identifier(identifier.clone()));
}
visit::visit_identifier(self, identifier);
}
Expand Down Expand Up @@ -174,6 +165,7 @@ impl NodeVisitor {
}
pub fn find(&mut self, src: &SourceUnit, source: &String) -> Option<InteractableNode> {
self.source = source.clone();
self.node = None;
self.visit_source_unit(src);
self.node.clone()
}
Expand Down
14 changes: 10 additions & 4 deletions libs/solc-references/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ pub enum InteractableNode {
FunctionCall(FunctionCall),
ModifierInvocation(ModifierInvocation),
InheritanceSpecifier(InheritanceSpecifier),
Identifier(Identifier, Box<InteractableNode>),
Identifier(Identifier),
MemberAccess(MemberAccess),
NewExpression(NewExpression, Box<InteractableNode>),
UserDefinedTypeName(UserDefinedTypeName),
IdentifierPath(IdentifierPath),
}

//macro to get the .id field of an interactable node
Expand All @@ -59,10 +61,12 @@ pub fn get_id(node: &InteractableNode) -> i64 {
InteractableNode::FunctionCall(node) => node.id,
InteractableNode::ModifierInvocation(node) => node.id,
InteractableNode::InheritanceSpecifier(node) => node.id,
InteractableNode::Identifier(node, _) => node.id,
InteractableNode::Identifier(node) => node.id,
InteractableNode::MemberAccess(node) => node.id,
InteractableNode::NewExpression(node, _) => node.id,
InteractableNode::ImportDirectiveAlias(node) => node.foreign.id,
InteractableNode::UserDefinedTypeName(udt) => udt.id,
InteractableNode::IdentifierPath(ip) => ip.id,
}
}

Expand Down Expand Up @@ -148,7 +152,7 @@ pub fn get_reference_id(node: &InteractableNode) -> Option<i64> {

}
},
InteractableNode::Identifier(node, _) => node.referenced_declaration,
InteractableNode::Identifier(node) => node.referenced_declaration,
InteractableNode::MemberAccess(node) => node.referenced_declaration,
// InteractableNode::NewExpression(node, _) => node.type_descriptions,
_ => None,
Expand All @@ -174,9 +178,11 @@ pub fn get_range(node: &InteractableNode) -> Range {
InteractableNode::FunctionCall(node) => source_location_to_range(&node.src),
InteractableNode::ModifierInvocation(node) => source_location_to_range(&node.src),
InteractableNode::InheritanceSpecifier(node) => source_location_to_range(&node.src),
InteractableNode::Identifier(node, _) => source_location_to_range(&node.src),
InteractableNode::Identifier(node) => source_location_to_range(&node.src),
InteractableNode::MemberAccess(node) => source_location_to_range(&node.src),
InteractableNode::NewExpression(node, _) => source_location_to_range(&node.src),
InteractableNode::ImportDirectiveAlias(node) => source_location_to_range(&node.foreign.src),
InteractableNode::UserDefinedTypeName(udt) => source_location_to_range(&udt.src),
InteractableNode::IdentifierPath(ip) => source_location_to_range(&ip.src),
}
}
83 changes: 32 additions & 51 deletions libs/solc-references/src/usages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,80 +7,61 @@ use crate::types::InteractableNode;
pub struct UsagesFinder {
pub id: i64,
pub to_find: Vec<InteractableNode>,
pub is_looking_for_type: bool,
}

impl <'ast> Visit<'ast> for UsagesFinder {
fn visit_contract_definition(&mut self, contract: &'ast ContractDefinition) {
if contract.id == self.id {
self.to_find.push(InteractableNode::ContractDefinition(contract.clone()));
}
visit::visit_contract_definition(self, contract);
}
fn visit_function_definition(&mut self, function: &'ast FunctionDefinition) {
if function.id == self.id {
self.to_find.push(InteractableNode::FunctionDefinition(function.clone()));
}
visit::visit_function_definition(self, function);
}
fn visit_modifier_definition(&mut self, modifier: &'ast ModifierDefinition) {
if modifier.id == self.id {
self.to_find.push(InteractableNode::ModifierDefinition(modifier.clone()));
}
visit::visit_modifier_definition(self, modifier);
}
fn visit_struct_definition(&mut self, struct_def: &'ast StructDefinition) {
if struct_def.id == self.id {
self.to_find.push(InteractableNode::StructDefinition(struct_def.clone()));
}
visit::visit_struct_definition(self, struct_def);
}
fn visit_enum_definition(&mut self, enum_def: &'ast EnumDefinition) {
if enum_def.id == self.id {
self.to_find.push(InteractableNode::EnumDefinition(enum_def.clone()));
}
visit::visit_enum_definition(self, enum_def);
fn visit_using_for_directive(&mut self, using_for: &'ast UsingForDirective) {
visit::visit_using_for_directive(self, using_for);
}
fn visit_variable_declaration(&mut self, variable: &'ast VariableDeclaration) {
if variable.id == self.id {
self.to_find.push(InteractableNode::VariableDeclaration(variable.clone()));

fn visit_identifier_path(&mut self,_path: &'ast IdentifierPath) {
if _path.referenced_declaration == self.id {
self.to_find.push(InteractableNode::IdentifierPath(_path.clone()));
}
visit::visit_variable_declaration(self, variable);
visit::visit_identifier_path(self, _path);
}
fn visit_event_definition(&mut self, event: &'ast EventDefinition) {
if event.id == self.id {
self.to_find.push(InteractableNode::EventDefinition(event.clone()));

fn visit_user_defined_type_name(&mut self,_udt: &'ast UserDefinedTypeName) {
if _udt.referenced_declaration == self.id {
self.to_find.push(InteractableNode::UserDefinedTypeName(_udt.clone()));
}
visit::visit_event_definition(self, event);
visit::visit_user_defined_type_name(self, _udt);
}
fn visit_enum_value(&mut self, enum_value: &'ast EnumValue) {
if enum_value.id == self.id {
self.to_find.push(InteractableNode::EnumValue(enum_value.clone()));
}
visit::visit_enum_value(self, enum_value);

fn visit_import_directive(&mut self, import: &'ast ImportDirective) {
visit::visit_import_directive(self, import);
}
fn visit_using_for_directive(&mut self, using_for: &'ast UsingForDirective) {
if using_for.id == self.id {
self.to_find.push(InteractableNode::UsingForDirective(using_for.clone()));

fn visit_identifier(&mut self,ident: &'ast Identifier) {
let node = InteractableNode::Identifier(ident.clone());
if ident.referenced_declaration.is_some_and(|id| self.id == id) {
self.to_find.push(node.clone());
}
visit::visit_using_for_directive(self, using_for);
visit::visit_identifier(self, ident);
}
fn visit_import_directive(&mut self, import: &'ast ImportDirective) {
if import.id == self.id {
self.to_find.push(InteractableNode::ImportDirective(import.clone()));

fn visit_member_access(&mut self,member: &'ast MemberAccess) {
let node = InteractableNode::MemberAccess(member.clone());
if member.referenced_declaration.is_some_and(|id| self.id == id) {
self.to_find.push(node.clone());
}
visit::visit_import_directive(self, import);
visit::visit_member_access(self, member);
}
}

impl UsagesFinder {
pub fn new(id: i64) -> Self {
pub fn new(id: i64, is_looking_for_type: bool) -> Self {
UsagesFinder {
id,
to_find: Vec::new(),
is_looking_for_type,
}
}

pub fn find(&mut self, ast: &SourceUnit) -> Vec<InteractableNode> {
self.to_find = Vec::new();
eprintln!("Finding usages inf file: {}", ast.id);
self.visit_source_unit(ast);
eprintln!("Nodes found for file with id {}: ", ast.id);
for node in &self.to_find {
Expand Down
12 changes: 11 additions & 1 deletion libs/solc-references/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

use crate::types::{Position, Range};
use crate::types::{InteractableNode, Position, Range};
use solc_ast_rs_types::types::SourceLocation;

pub fn is_node_in_range(node: &SourceLocation, position: &Position, source: &str) -> bool {
Expand Down Expand Up @@ -55,4 +55,14 @@ pub fn index_to_position(index: u32, source: &str) -> Position {
}
}
Position { line, column }
}

pub fn is_node_a_type(node: &InteractableNode) -> bool {
match node {
InteractableNode::ContractDefinition(_) => true,
InteractableNode::StructDefinition(_) => true,
InteractableNode::ModifierDefinition(_) => true,
InteractableNode::EventDefinition(_) => true,
_ => false
}
}
2 changes: 1 addition & 1 deletion libs/solc-wrapper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ edition = "2021"

[dependencies]
serde_json = "1.0.113"
solc-ast-rs-types = "0.1.2"
solc-ast-rs-types = "0.1.6"
thiserror = "1.0.56"
8 changes: 6 additions & 2 deletions libs/solc-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod forge;
mod error;
mod output;
mod utils;

pub use error::SolcWrapperError;
use forge::*;
Expand Down Expand Up @@ -40,15 +41,18 @@ pub fn get_ast_from_solc_output(base_path: String) -> Result<Vec<SolcAstFile>, S
let files = get_files_from_solc_output(&base_path)?;
let mut ast_files = Vec::new();
for file in files {
if file.file.contains("safeconsole.sol") {
continue;
}
let ast: SourceUnit = serde_json::from_value(file.clone().json).map_err(|e| {
eprintln!("Error while parsing json ast: {:?},\n json: {}", e, file.json);
eprintln!("Error while parsing json ast in file '{}': {:?}", file.file, e);
e
})?;
let out_path = &file.file;
ast_files.push(SolcAstFile {
file: SolcFile {
path: out_path.clone(),
content: std::fs::read_to_string(&out_path).map_err(|e| {
content: std::fs::read_to_string( std::path::Path::new(&base_path).join(&out_path)).map_err(|e| {
eprintln!("Error reading compiled file : {}", e);
SolcWrapperError::ReadSourceFile(e)
})?,
Expand Down
6 changes: 5 additions & 1 deletion libs/solc-wrapper/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ use std::fs::{read_dir, DirEntry};
use crate::SolcJsonFile;
use crate::error::SolcWrapperError;
use serde_json;
use crate::utils::join_path;

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)? {
if file.contains("safeconsole.sol") {
continue;
}
files.push(SolcJsonFile {
json: json["ast"].clone(),
file: file.clone()
file: join_path(base_path, &file),
});
};

Expand Down
7 changes: 7 additions & 0 deletions libs/solc-wrapper/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use std::path::PathBuf;

pub fn join_path(base_path: &str, file: &str) -> String {
let mut path = PathBuf::from(base_path);
path.push(file);
path.to_str().unwrap().to_string().replace("\\", "/")
}
13 changes: 11 additions & 2 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 @@ -75,7 +75,7 @@ impl LanguageServer for Backend {
let mut position = params.text_document_position.position;
position.line += 1;
position.character += 1;
let locations = self.references_provider.lock().await.get_references(solc_references::Position { line: position.line, column: position.character });
let locations = self.references_provider.lock().await.get_references(&normalize_path(uri.path()), solc_references::Position { line: position.line, column: position.character });
let ret: Vec<LspLocation> = locations.iter().map(|location| {
let mut new_uri = uri.clone();
new_uri.set_path(&location.uri);
Expand Down

0 comments on commit 270fb24

Please sign in to comment.