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

49 - Solidity Linter #89

Merged
merged 61 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
fe3771b
chore: create branch feature/49-solidity-linter-staging
Aug 30, 2023
d795be7
chore: create branch feature/49-solidity-linter/75-refactor-solidhunt…
Aug 30, 2023
e260003
refactor: fix all lint errors and a few compiler warnings
0xtekgrinder Sep 4, 2023
f738938
refactor: rename LintError to SolidHunterError
Leon-azerty Sep 7, 2023
7f3438b
refactor: rename and move errors
Leon-azerty Sep 7, 2023
864cd34
refactor(solidhunter): clean linter.rs
0xtekgrinder Sep 6, 2023
97dfb14
refactor(solidhunter): refactor LintDiag and a few other things
0xtekgrinder Sep 7, 2023
9b2df10
refactor: renamed invalid error enum name
EnergyCube Sep 7, 2023
0ffd488
refactor(solidhunter): clean up the Factory and apply a default impl
0xtekgrinder Sep 7, 2023
c6dc87c
refactor(solidhunter): SolidHunterError moved to errors.rs & fixed wa…
EnergyCube Sep 7, 2023
dac3049
refactor(solidity/linter/core): unified error types
Leon-azerty Sep 7, 2023
7a522cd
refactor(solidhunter): remove usless unwrap
0xtekgrinder Sep 7, 2023
54ef01e
chore(solidity/linter): cleaned and linted code
0xSwapFeeder Sep 8, 2023
40eb1d8
refactor(solidity/linter/core): added missing indentation
0xmemorygrinder Sep 9, 2023
38b541b
chore(solidity/linter): extracted linter diag creation from naming an…
0xSwapFeeder Sep 9, 2023
7092ccc
chore(solidity/linter): extracted linter diag creation from best prac…
EnergyCube Sep 9, 2023
3ca620c
refactor(solidhunter): rename errors file into error
0xtekgrinder Sep 10, 2023
f58af1e
fix(solidity/linter/core): fixed all compilation issues
0xmemorygrinder Sep 10, 2023
644b521
tests(solidhunter): add test engine
0xtekgrinder Sep 12, 2023
2d59a35
refactor(solidhunter): clean solidhunter-lib
0xtekgrinder Sep 12, 2023
e8ade81
revert: SolidHunter::IoError
0xtekgrinder Sep 12, 2023
6e1b2cf
feat(solidhunter): update test engine to search for the finding
0xtekgrinder Sep 13, 2023
511e80c
chore(solidhunter): remove removeme file
0xtekgrinder Sep 13, 2023
cbf1351
chore: create branch feature/49-solidity-linter/69-use-ast-crate-in-s…
Sep 13, 2023
06e4dfa
refactor(ast-extractor): make the lib easier to use with errors aside…
0xtekgrinder Sep 14, 2023
6294a4c
refactor(solidhunter): remove solc_wrappêr and replace it with ast_ex…
0xtekgrinder Sep 14, 2023
40fd906
refactor(ast-extractor): change mod.rd into retriever.rs
0xtekgrinder Sep 14, 2023
c97828c
feat(libs/ast-extractor): export LineColumn type for code location
0xmemorygrinder Sep 15, 2023
5b6130e
feat(libs/ast-extractor): added util method on range to compute easil…
0xmemorygrinder Sep 15, 2023
9acf77d
refactor(solidity/linter/core): import-on-top rule now uses ast crate…
0xmemorygrinder Sep 15, 2023
7dc005f
feat(ast-extractor): use refs for all retrievers
0xtekgrinder Sep 15, 2023
d020796
refactor(solidhunter): remove length attribute from Range type
0xtekgrinder Sep 15, 2023
92d4ffc
refactor(solidhunter): contract_name_pascalcase use ast_extractor
0xtekgrinder Sep 15, 2023
cfc05e0
tests(solidhunter): update tests accordingly to last few changes
0xtekgrinder Sep 15, 2023
c881d06
refactor(solidity/linter/core): made function-max-lines use ast crate
0xmemorygrinder Sep 15, 2023
e0c268d
refactor(solidity/linter/core): max-states-count rule now uses ast crate
0xmemorygrinder Sep 15, 2023
ee0ba07
refactor(solidity/linter/core): use LineColumn instead of Range
0xtekgrinder Sep 15, 2023
d745f20
feat(solidity/linter/core): FunctionNameCamelCase rule with alloy
0xtekgrinder Sep 15, 2023
9fd7022
feat(solidity/linter/core): func-param-camel-case rule
0xtekgrinder Sep 15, 2023
ca53f87
feat(solidity/linter/core): add UseForbiddenName rule with alloy
0xtekgrinder Sep 15, 2023
9299e15
feat(solidity/linter/core): added WIP ReasonString rule with alloy
EnergyCube Sep 16, 2023
e73f9ad
feat(solidhunter): fixed tests folder listing
EnergyCube Sep 16, 2023
9e4b69c
feat(solidity/linter/core): completed ReasonString rule with alloy
EnergyCube Sep 16, 2023
f199786
chore(solidity/linter): created a get_call_expressions custom visitor
0xSwapFeeder Sep 20, 2023
8a941da
refactor(solidity/linter/core): fix lcippy warnings and change u64 to…
0xtekgrinder Sep 20, 2023
593a175
refactor(solidity/linter/core): rename error into errors
0xtekgrinder Sep 20, 2023
53d29fb
feat(solidity/linter/core): add missing directory in tests
0xtekgrinder Sep 20, 2023
e7b691a
fix(solidity.linter/core): can parse a folder
0xtekgrinder Sep 20, 2023
4221e90
tests(solidity/linter/core): add all rules to be sure everything work…
0xtekgrinder Sep 20, 2023
912caac
fix(solidity/linter/core): fixed LintDiag formatting
0xmemorygrinder Sep 20, 2023
40445fe
fix(solidity/linter/core): line of linter formatting is now good
0xtekgrinder Sep 21, 2023
59d3af3
chore: remove remove-me
0xtekgrinder Sep 21, 2023
c6acb23
Merge pull request #93 from astrodevs-labs/feature/49-solidity-linter…
0xtekgrinder Sep 23, 2023
bf698e5
chore: create branch feature/49-solidity-linter/131-default-rules-are…
Sep 26, 2023
684f24b
fix(solidity/linter/core): doesn't create a new file when running the…
0xmemorygrinder Sep 29, 2023
ec6a83a
fix(solidity/linter/core): doesn't create a file when none are specif…
0xtekgrinder Sep 28, 2023
a4457f0
chore: deleted remove-me.txt
0xmemorygrinder Sep 29, 2023
656d786
Merge pull request #133 from astrodevs-labs/feature/49-solidity-linte…
0xtekgrinder Sep 29, 2023
32889a7
fix(ci): now track extension subfolders as part of extension workspace
0xmemorygrinder Sep 29, 2023
47df9ef
refactor(solidity/linter/core): fixed linting errors
0xmemorygrinder Sep 29, 2023
fb9e89c
chore: deleted remove-me
0xmemorygrinder Sep 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions .github/workflows/detect-workspace-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,62 @@ jobs:
console.log(workspaces)
const affectedWorkspaces = workspaces.filter(workspace => {
return workspace.location !== '.'
}).map(workspace => {
return {
name: workspace.name
}
})
console.log(affectedWorkspaces)
const toolchainsWorkspaces = affectedWorkspaces.filter(workspace => {
return workspace.name.startsWith('@osmium-toolchains/')
})
}).map(workspace => ({
name: workspace.name
}))
const librariesWorkspaces = affectedWorkspaces.filter(workspace => {
return workspace.name.startsWith('@osmium-libs/')
})
}).map(workspace => ({
name: workspace.name
}))
const packagesWorkspaces = affectedWorkspaces.filter(workspace => {
return workspace.name.startsWith('@osmium-packages/')
})
}).map(workspace => ({
name: workspace.name
}))
const extensionsWorkspaces = affectedWorkspaces.filter(workspace => {
return workspace.name.match(/@osmium\/(?:manager|(?!\w+-\w+-\w+)(?:\w+-\w+))/)
}).map(workspace => ({
name: workspace.name
}))
const extensionsFoldersWorkspaces = affectedWorkspaces.filter(workspace => {
return workspace.name.match(/@osmium\/\w+-\w+-\w+/)
}).map(workspace => ({
name: workspace.name
}))

const missingExtensionsWorkspaces = extensionsFoldersWorkspaces.map(workspaceFolder => {
const extensionName = workspaceFolder.name.split('-').slice(0, 2).join('-')
const extensionWorkspace = extensionsWorkspaces.find(workspace => {
return workspace.name === extensionName
})
if (!extensionWorkspace) {
return {
name: extensionName
}
}
return extensionWorkspace
})

const completeList = [...extensionsWorkspaces, ...missingExtensionsWorkspaces]
const completeExtensionsWorkspaces = completeList.filter((workspace, index, self) => {
return index === self.findIndex((t) => (
t.name === workspace.name
))
})

return {
affectedWorkspaces,
toolchainsWorkspaces,
extensionsWorkspaces,
extensionsWorkspaces: completeExtensionsWorkspaces,
librariesWorkspaces,
packagesWorkspaces
}
Expand Down
11 changes: 11 additions & 0 deletions libs/ast-extractor/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use proc_macro2::LexError;
use syn::Error;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ExtractError {
#[error("Tokenization error: {0}")]
Tokenize(#[from] LexError),
#[error("Parsing error")]
Parse(#[from] Error),
}
31 changes: 11 additions & 20 deletions libs/ast-extractor/src/extract.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
use proc_macro2::{LexError, TokenStream};
/**
* extract.rs
* Extract AST from solidity source code
* author: 0xMemoryGrinder
*/
*/
use crate::errors::ExtractError;
use proc_macro2::TokenStream;
use std::str::FromStr;
use syn::Error;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum ExtractError {
#[error("Tokenization error: {0}")]
Tokenize(#[from] LexError),
#[error("Parsing error")]
Parse(#[from] Error),
}

pub fn extract_ast_from(source: String) -> Result<syn_solidity::File, ExtractError> {
let tokens = TokenStream::from_str(source.as_str())?;
pub fn extract_ast_from_content(content: &str) -> Result<syn_solidity::File, ExtractError> {
let tokens = TokenStream::from_str(content)?;
let ast = syn_solidity::parse2(tokens)?;
Ok(ast)
}
Expand All @@ -29,20 +20,20 @@ mod tests {
use std::path::PathBuf;

#[test]
fn test_extract_ast_from_good() {
fn test_extract_ast_from_content_good() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests");
path.push("files");
path.push("good.sol");
let source = fs::read_to_string(path).unwrap();
let res = extract_ast_from(source);
let res = extract_ast_from_content(&source);
assert!(res.is_ok());
}

#[test]
fn test_extract_ast_from_invalid_token() {
fn test_extract_ast_from_content_invalid_token() {
let source = String::from("contract test { function test() public | uint a = 1 } }");
let result = extract_ast_from(source);
let result = extract_ast_from_content(&source);
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
Expand All @@ -51,9 +42,9 @@ mod tests {
}

#[test]
fn test_extract_ast_from_missing_semicolumn() {
fn test_extract_ast_from_content_missing_semicolumn() {
let source = String::from("contract test { function test() public { uint a = 1 } }");
let result = extract_ast_from(source);
let result = extract_ast_from_content(&source);
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Parsing error");
}
Expand Down
7 changes: 7 additions & 0 deletions libs/ast-extractor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
pub mod errors;
pub mod extract;
pub mod retriever;

// Expose syn_solidity crate
pub use syn_solidity::*;

// Publish span location type
pub use proc_macro2::LineColumn;
5 changes: 0 additions & 5 deletions libs/ast-extractor/src/retriever.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* retriever.rs
* Module for all AST utils functions
* author: 0xMemoryGrinder
*/
mod contract;
pub use contract::*;

Expand Down
10 changes: 5 additions & 5 deletions libs/ast-extractor/src/retriever/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ impl<'ast> Visit<'ast> for ContractVisitor {
}
}

pub fn retrieve_contract_nodes(ast: syn_solidity::File) -> Vec<ItemContract> {
pub fn retrieve_contract_nodes(ast: &syn_solidity::File) -> Vec<ItemContract> {
let mut visitor = ContractVisitor::new();
visitor.visit_file(&ast);
visitor.visit_file(ast);
visitor.contracts
}

Expand All @@ -44,7 +44,7 @@ mod tests {
let source = String::from("pragma solidity ^0.8.0;");
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();
let res = retrieve_contract_nodes(ast);
let res = retrieve_contract_nodes(&ast);
assert_eq!(res.len(), 0);
}

Expand All @@ -58,7 +58,7 @@ mod tests {
let source = fs::read_to_string(path).unwrap();
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();
let res = retrieve_contract_nodes(ast);
let res = retrieve_contract_nodes(&ast);
assert_eq!(res.len(), 1);
}

Expand All @@ -72,7 +72,7 @@ mod tests {
let source = fs::read_to_string(path).unwrap();
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();
let res = retrieve_contract_nodes(ast);
let res = retrieve_contract_nodes(&ast);
assert_eq!(res.len(), 2);
}
}
16 changes: 8 additions & 8 deletions libs/ast-extractor/src/retriever/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ impl<'ast> Visit<'ast> for EnumVisitor {
}
}

pub fn retrieve_enums_contract_nodes(ast: syn_solidity::ItemContract) -> Vec<ItemEnum> {
pub fn retrieve_enums_contract_nodes(ast: &syn_solidity::ItemContract) -> Vec<ItemEnum> {
let mut visitor = EnumVisitor::new();
visitor.visit_item_contract(&ast);
visitor.visit_item_contract(ast);
visitor.contract_enums
}

pub fn retrieve_enums_file_nodes(ast: syn_solidity::File) -> Vec<ItemEnum> {
pub fn retrieve_enums_file_nodes(ast: &syn_solidity::File) -> Vec<ItemEnum> {
let mut visitor = EnumVisitor::new();
visitor.visit_file(&ast);
visitor.visit_file(ast);
visitor.file_enums
}

Expand All @@ -73,7 +73,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_enums_contract_nodes(contract);
let res = retrieve_enums_contract_nodes(&contract);
assert_eq!(res.len(), 0);
} else {
panic!("Item shouldn't have enum");
Expand All @@ -98,7 +98,7 @@ mod tests {
.clone();

if let Item::Contract(contract) = contract {
let res = retrieve_enums_contract_nodes(contract);
let res = retrieve_enums_contract_nodes(&contract);
assert_eq!(res.len(), 1);
} else {
panic!("Item should have a contract");
Expand All @@ -116,7 +116,7 @@ mod tests {
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();

let res = retrieve_enums_file_nodes(ast);
let res = retrieve_enums_file_nodes(&ast);
assert_eq!(res.len(), 0);
}

Expand All @@ -131,7 +131,7 @@ mod tests {
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();

let res = retrieve_enums_file_nodes(ast);
let res = retrieve_enums_file_nodes(&ast);
assert_eq!(res.len(), 1);
}
}
8 changes: 4 additions & 4 deletions libs/ast-extractor/src/retriever/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ impl<'ast> Visit<'ast> for ErrorVisitor {
}
}

pub fn retrieve_errors_nodes(ast: syn_solidity::ItemContract) -> Vec<ItemError> {
pub fn retrieve_errors_nodes(ast: &syn_solidity::ItemContract) -> Vec<ItemError> {
let mut visitor = ErrorVisitor::new();
visitor.visit_item_contract(&ast);
visitor.visit_item_contract(ast);
visitor.errors
}

Expand All @@ -51,7 +51,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_errors_nodes(contract);
let res = retrieve_errors_nodes(&contract);
assert_eq!(res.len(), 0);
} else {
panic!("Item should not have error");
Expand All @@ -76,7 +76,7 @@ mod tests {
.clone();

if let Item::Contract(contract) = item {
let res = retrieve_errors_nodes(contract);
let res = retrieve_errors_nodes(&contract);
assert_eq!(res.len(), 1);
} else {
panic!("Item should have a contract");
Expand Down
16 changes: 8 additions & 8 deletions libs/ast-extractor/src/retriever/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ impl<'ast> Visit<'ast> for EventVisitor {
}
}

pub fn retrieve_events_contract_nodes(ast: syn_solidity::ItemContract) -> Vec<ItemEvent> {
pub fn retrieve_events_contract_nodes(ast: &syn_solidity::ItemContract) -> Vec<ItemEvent> {
let mut visitor = EventVisitor::new();
visitor.visit_item_contract(&ast);
visitor.visit_item_contract(ast);
visitor.contract_events
}

pub fn retrieve_events_file_nodes(ast: syn_solidity::File) -> Vec<ItemEvent> {
pub fn retrieve_events_file_nodes(ast: &syn_solidity::File) -> Vec<ItemEvent> {
let mut visitor = EventVisitor::new();
visitor.visit_file(&ast);
visitor.visit_file(ast);
visitor.file_events
}

Expand Down Expand Up @@ -74,7 +74,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_events_contract_nodes(contract);
let res = retrieve_events_contract_nodes(&contract);
assert_eq!(res.len(), 0);
} else {
panic!("Item should not have event");
Expand All @@ -99,7 +99,7 @@ mod tests {
.clone();

if let Item::Contract(contract) = item {
let res = retrieve_events_contract_nodes(contract);
let res = retrieve_events_contract_nodes(&contract);
assert_eq!(res.len(), 1);
} else {
panic!("Item should have a event");
Expand All @@ -117,7 +117,7 @@ mod tests {
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();

let res = retrieve_events_file_nodes(ast);
let res = retrieve_events_file_nodes(&ast);
assert_eq!(res.len(), 0);
}

Expand All @@ -132,7 +132,7 @@ mod tests {
let tokens = TokenStream::from_str(source.as_str()).unwrap();
let ast = syn_solidity::parse2(tokens).unwrap();

let res = retrieve_events_file_nodes(ast);
let res = retrieve_events_file_nodes(&ast);
assert_eq!(res.len(), 1);
}
}
10 changes: 5 additions & 5 deletions libs/ast-extractor/src/retriever/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ impl<'ast> Visit<'ast> for FunctionVisitor {
}
}

pub fn retrieve_functions_nodes(ast: syn_solidity::ItemContract) -> Vec<ItemFunction> {
pub fn retrieve_functions_nodes(ast: &syn_solidity::ItemContract) -> Vec<ItemFunction> {
let mut visitor = FunctionVisitor::new();
visitor.visit_item_contract(&ast);
visitor.visit_item_contract(ast);
visitor.functions
}

Expand All @@ -53,7 +53,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_functions_nodes(contract);
let res = retrieve_functions_nodes(&contract);
assert_eq!(res.len(), 0);
} else {
panic!("Item is not a contract");
Expand All @@ -73,7 +73,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_functions_nodes(contract);
let res = retrieve_functions_nodes(&contract);
assert_eq!(res.len(), 1);
} else {
panic!("Item is not a contract");
Expand All @@ -93,7 +93,7 @@ mod tests {
let item = ast.items.first().unwrap().clone();

if let Item::Contract(contract) = item {
let res = retrieve_functions_nodes(contract);
let res = retrieve_functions_nodes(&contract);
assert_eq!(res.len(), 2);
} else {
panic!("Item is not a contract");
Expand Down
Loading