Skip to content

Commit

Permalink
Update yul crate, some more work on AST building code, some cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
camden-smallwood committed Jun 9, 2023
1 parent 68cf43f commit 0a39d3a
Show file tree
Hide file tree
Showing 12 changed files with 918 additions and 207 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ Some legacy versions of Solidity are inherently supported (0.5.X-0.7.X), but the
cargo run --release -- \
[--todo_list] \
[--contract=<contract_name>] \
[--output_format=<plain_text | json>]
[--output_format=<plain_text | json>] \
[--analyzer_name1] \
[--analyzer_nameN] \
[--contract_path=<Contract.sol>] \
<project_directory>
```

Expand Down
6 changes: 6 additions & 0 deletions eth-lang-utils/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,14 @@ pub enum NodeType {
InlineAssembly,
YulLiteral,
YulTypedName,
YulIf,
YulSwitch,
YulCase,
YulForLoop,
YulBreak,
YulContinue,
YulLeave,
YulFunctionDefinition,
YulFunctionCall,
YulExpressionStatement,
YulAssignment,
Expand Down
1 change: 1 addition & 0 deletions solast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
simd-json = "0.7"
eth-lang-utils = { path = "../eth-lang-utils" }
solang-parser = "0.3.0"
solidity = { path = "../solidity" }
yul = { path = "../yul" }
primitive-types = "0.10.1"
2 changes: 1 addition & 1 deletion solast/src/analysis/ineffectual_statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl IneffectualStatementsVisitor {
source_unit_path,
Some(source_line),
format!(
"\t{} contains an ineffectual {} statement: `{}`",
"{} contains an ineffectual {} statement: `{}`",
contract_definition.definition_node_location(definition_node),
description,
expression
Expand Down
2 changes: 1 addition & 1 deletion solast/src/analysis/no_spdx_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl AstVisitor for NoSpdxIdentifierVisitor {
self.report.borrow_mut().add_entry(
context.current_source_unit.absolute_path.clone().unwrap_or_else(String::new),
None,
"\tSPDX license identifier not provided in source file; Consider adding one before deployment"
"SPDX license identifier not provided in source file; Consider adding one before deployment"
);
}

Expand Down
2 changes: 1 addition & 1 deletion solast/src/analysis/tight_variable_packing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ impl AstVisitor for TightVariablePackingVisitor {

if has_loose_variable_packing {
// TODO: only print when this works...
// println!("\t{:?} {} has loose variable packing", context.contract_definition.kind, context.contract_definition.name);
// println!("{:?} {} has loose variable packing", context.contract_definition.kind, context.contract_definition.name);
}

Ok(())
Expand Down
214 changes: 126 additions & 88 deletions solast/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fn main() -> io::Result<()> {
let mut visitor_names: HashSet<String> = HashSet::new();
let mut contract_name: Option<String> = None;
let mut output_format = OutputFormat::PlainText;
let mut contract_paths = vec![];

for arg in args {
match arg {
Expand All @@ -52,6 +53,10 @@ fn main() -> io::Result<()> {
contract_name = Some(s.trim_start_matches("contract=").into());
}

s if s.starts_with("contract-path=") || s.starts_with("contract_path=") => {
contract_paths.push(PathBuf::from(&arg.as_str()[16..]));
}

s if s.starts_with("output-format=") || s.starts_with("output_format=") => {
output_format = OutputFormat::try_from(&arg.as_str()[16..])?;
}
Expand All @@ -77,144 +82,177 @@ fn main() -> io::Result<()> {
}
}

let path = match path {
Some(path) => path,
None => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Path not supplied"))
};

if !path.exists() {
return Err(io::Error::new(io::ErrorKind::NotFound, path.to_string_lossy()))
}

let mut source_units: Vec<SourceUnit> = vec![];

let brownie_config_path = path.join("brownie-config.yaml");
let hardhat_config_js_path = path.join("hardhat.config.js");
let hardhat_config_ts_path = path.join("hardhat.config.ts");
let truffle_config_path = path.join("truffle-config.js");
if contract_paths.is_empty() {
let path = match path {
Some(path) => path,
None => return Err(io::Error::new(io::ErrorKind::InvalidInput, "Path not supplied"))
};

if brownie_config_path.is_file() {
//
// TODO: load the brownie config and get the actual build paths
//
if !path.exists() {
return Err(io::Error::new(io::ErrorKind::NotFound, path.to_string_lossy()))
}

let brownie_config_path = path.join("brownie-config.yaml");
let hardhat_config_js_path = path.join("hardhat.config.js");
let hardhat_config_ts_path = path.join("hardhat.config.ts");
let truffle_config_path = path.join("truffle-config.js");

if brownie_config_path.is_file() {
//
// TODO: load the brownie config and get the actual build paths
//

let build_paths = &[
path.join("build").join("contracts"),
path.join("build").join("interfaces"),
];

for build_path in build_paths {
if !build_path.exists() || !build_path.is_dir() {
todo!("brownie project not compiled")
}

for path in std::fs::read_dir(build_path)? {
let path = path?.path();

if !path.is_file() || !path.extension().map(|extension| extension == "json").unwrap_or(false) {
continue;
}

let file: brownie::File = simd_json::from_reader(File::open(path)?)?;

let build_paths = &[
path.join("build").join("contracts"),
path.join("build").join("interfaces"),
];
if let Some(mut source_unit) = file.ast {
if let Some(contract_name) = contract_name.as_deref() {
if !source_unit.contract_definitions().iter().any(|c| c.name == contract_name) {
continue;
}
}

if !source_units.iter().any(|existing_source_unit| existing_source_unit.absolute_path == source_unit.absolute_path) {
source_unit.source = file.source.clone();
source_units.push(source_unit);
}
}
}
}
} else if hardhat_config_js_path.is_file() || hardhat_config_ts_path.is_file() {
let build_path = path.join("artifacts").join("build-info");

for build_path in build_paths {
if !build_path.exists() || !build_path.is_dir() {
todo!("brownie project not compiled")
todo!("hardhat project not compiled")
}

let console_path = PathBuf::new()
.join("hardhat")
.join("console.sol")
.to_string_lossy()
.to_string();

for path in std::fs::read_dir(build_path)? {
let path = path?.path();

if !path.is_file() || !path.extension().map(|extension| extension == "json").unwrap_or(false) {
continue;
}

let file: brownie::File = simd_json::from_reader(File::open(path)?)?;
let file: hardhat::File = simd_json::from_reader(File::open(path)?)?;

if let Some(mut source_unit) = file.ast {
for (source_path, source) in file.output.sources {
let mut source_unit = source.ast;

if source_unit.absolute_path.as_deref().unwrap_or("").ends_with(console_path.as_str()) {
continue;
}

if let Some(contract_name) = contract_name.as_deref() {
if !source_unit.contract_definitions().iter().any(|c| c.name == contract_name) {
continue;
}
}

if !source_units.iter().any(|existing_source_unit| existing_source_unit.absolute_path == source_unit.absolute_path) {
source_unit.source = file.source.clone();
source_units.push(source_unit);
if let Some(source) = file.input.sources.get(&source_path) {
source_unit.source = Some(source.content.clone());
source_units.push(source_unit);
}
}
}
}
}
} else if hardhat_config_js_path.is_file() || hardhat_config_ts_path.is_file() {
let build_path = path.join("artifacts").join("build-info");

if !build_path.exists() || !build_path.is_dir() {
todo!("hardhat project not compiled")
}
} else if truffle_config_path.is_file() {
let build_path = path.join("build").join("contracts");

let console_path = PathBuf::new()
.join("hardhat")
.join("console.sol")
.to_string_lossy()
.to_string();

for path in std::fs::read_dir(build_path)? {
let path = path?.path();

if !path.is_file() || !path.extension().map(|extension| extension == "json").unwrap_or(false) {
continue;
if !build_path.exists() || !build_path.is_dir() {
todo!("truffle project not compiled")
}

let file: hardhat::File = simd_json::from_reader(File::open(path)?)?;
let migrations_path = PathBuf::new()
.join("contracts")
.join("Migrations.sol")
.to_string_lossy()
.to_string();

for (source_path, source) in file.output.sources {
let mut source_unit = source.ast;
for path in std::fs::read_dir(build_path)? {
let path = path?.path();

if source_unit.absolute_path.as_deref().unwrap_or("").ends_with(console_path.as_str()) {
if !path.is_file() || !path.extension().map(|extension| extension == "json").unwrap_or(false) {
continue;
}

if let Some(contract_name) = contract_name.as_deref() {
if !source_unit.contract_definitions().iter().any(|c| c.name == contract_name) {

let file: truffle::File = simd_json::from_reader(File::open(path)?)?;

if let Some(mut source_unit) = file.ast {
if source_unit.absolute_path.as_deref().unwrap_or("").ends_with(migrations_path.as_str()) {
continue;
}
}

if let Some(contract_name) = contract_name.as_deref() {
if !source_unit.contract_definitions().iter().any(|c| c.name == contract_name) {
continue;
}
}

if !source_units.iter().any(|existing_source_unit| existing_source_unit.absolute_path == source_unit.absolute_path) {
if let Some(source) = file.input.sources.get(&source_path) {
source_unit.source = Some(source.content.clone());
if !source_units.iter().any(|existing_source_unit| existing_source_unit.absolute_path == source_unit.absolute_path) {
source_unit.source = file.source.clone();
source_units.push(source_unit);
}
}
}
} else {
unimplemented!("no supported project configuration found")
}
} else if truffle_config_path.is_file() {
let build_path = path.join("build").join("contracts");

if !build_path.exists() || !build_path.is_dir() {
todo!("truffle project not compiled")
}
} else {
let mut file_no = 0;

let migrations_path = PathBuf::new()
.join("contracts")
.join("Migrations.sol")
.to_string_lossy()
.to_string();
for contract_path in contract_paths {
let src = std::fs::read_to_string(contract_path.clone())?;

for path in std::fs::read_dir(build_path)? {
let path = path?.path();
let (source_unit, comments) = solang_parser::parse(src.as_str(), file_no)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, format!("Failed to parse contract \"{}\"", contract_path.to_string_lossy())))?;

if !path.is_file() || !path.extension().map(|extension| extension == "json").unwrap_or(false) {
continue;
}
let mut builder = AstBuilder::default();
let mut source_unit = builder.build_source_unit(&source_unit);

let file: truffle::File = simd_json::from_reader(File::open(path)?)?;
let mut license = None;

if let Some(mut source_unit) = file.ast {
if source_unit.absolute_path.as_deref().unwrap_or("").ends_with(migrations_path.as_str()) {
continue;
}

if let Some(contract_name) = contract_name.as_deref() {
if !source_unit.contract_definitions().iter().any(|c| c.name == contract_name) {
continue;
for comment in comments.iter() {
if let solang_parser::pt::Comment::Line(_, text) = comment {
let text = text.trim_start_matches("//").trim_start_matches(' ');
if text.starts_with("SPDX-License-Identifier:") {
license = Some(text.trim_start_matches("SPDX-License-Identifier:").trim_start_matches(' ').to_string());
}
}

if !source_units.iter().any(|existing_source_unit| existing_source_unit.absolute_path == source_unit.absolute_path) {
source_unit.source = file.source.clone();
source_units.push(source_unit);
}
}

source_unit.absolute_path = Some(contract_path.to_string_lossy().to_string());
source_unit.source = Some(src);
source_unit.license = license;

source_units.push(source_unit);

file_no += 1;
}
} else {
unimplemented!("no supported project configuration found")
}

source_units.sort_by(|lhs, rhs| {
Expand Down
1 change: 0 additions & 1 deletion solidity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ edition = "2021"
eth-lang-utils = { path = "../eth-lang-utils" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
simd-json = "0.7"
solang-parser = "0.3.0"
yul = { path = "../yul" }
Loading

0 comments on commit 0a39d3a

Please sign in to comment.