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

113 - Var Name MixedCase Rule #154

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions libs/ast-extractor/src/retriever.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
mod contract;
pub use contract::*;

mod variable_definition;
pub use variable_definition::*;

mod variable_declaration;
pub use variable_declaration::*;

mod r#enum;
pub use r#enum::*;

Expand Down
64 changes: 64 additions & 0 deletions libs/ast-extractor/src/retriever/variable_declaration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* variable_declaration.rs
* Function to retrieve variable nodes from AST
* author: Leon
*/
use syn_solidity::{VariableDeclaration, Visit};

struct VariableDeclarationVisitor {
variables: Vec<VariableDeclaration>,
}

impl VariableDeclarationVisitor {
pub fn new() -> Self {
Self {
variables: Vec::new(),
}
}
}

impl<'ast> Visit<'ast> for VariableDeclarationVisitor {
fn visit_variable_declaration(&mut self, i: &VariableDeclaration) {
self.variables.push(i.clone());
syn_solidity::visit::visit_variable_declaration(self, i);
}
}

pub fn retrieve_variable_declaration_nodes(ast: &syn_solidity::File) -> Vec<VariableDeclaration> {
let mut visitor = VariableDeclarationVisitor::new();
visitor.visit_file(ast);
visitor.variables
}

#[cfg(test)]
mod tests {
use proc_macro2::TokenStream;

use super::*;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;

// #[test]
// fn test_retrieve_variable_declaration_nodes_empty() {
// 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_variable_declaration_nodes(&ast);
// assert_eq!(res.len(), 0);
// }

#[test]
fn test_retrieve_variable_declaration_nodes_two() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests");
path.push("files");
path.push("variables_declaration");
path.push("file.sol");
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_variable_declaration_nodes(&ast);
assert_eq!(res.len(), 2);
}
}
64 changes: 64 additions & 0 deletions libs/ast-extractor/src/retriever/variable_definition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* variable.rs
* Function to retrieve variable definition nodes from AST
* author: Leon
*/
use syn_solidity::{VariableDefinition, Visit};

struct VariableDefinitionVisitor {
variables: Vec<VariableDefinition>,
}

impl VariableDefinitionVisitor {
pub fn new() -> Self {
Self {
variables: Vec::new(),
}
}
}

impl<'ast> Visit<'ast> for VariableDefinitionVisitor {
fn visit_variable_definition(&mut self, i: &VariableDefinition) {
self.variables.push(i.clone());
syn_solidity::visit::visit_variable_definition(self, i);
}
}

pub fn retrieve_variable_definition_nodes(ast: &syn_solidity::File) -> Vec<VariableDefinition> {
let mut visitor = VariableDefinitionVisitor::new();
visitor.visit_file(ast);
visitor.variables
}

#[cfg(test)]
mod tests {
use proc_macro2::TokenStream;

use super::*;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;

#[test]
fn test_retrieve_variable_definition_nodes_empty() {
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_variable_definition_nodes(&ast);
assert_eq!(res.len(), 0);
}

#[test]
fn test_retrieve_variable_definition_nodes_one() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("tests");
path.push("files");
path.push("variables_definition");
path.push("file.sol");
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_variable_definition_nodes(&ast);
assert_eq!(res.len(), 1);
}
}
8 changes: 8 additions & 0 deletions libs/ast-extractor/tests/files/variables_declaration/file.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
abstract contract Test {
uint256 public a;

function add() public view returns (uint256) {
uint256 b = 1;
return a + b;
}
}
8 changes: 8 additions & 0 deletions libs/ast-extractor/tests/files/variables_definition/file.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
abstract contract Test {
uint256 public a;

function add() public view returns (uint256) {
uint256 b = 1;
return a + b;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::rules::naming::func_name_camelcase::FuncNameCamelCase;
use crate::rules::naming::func_param_name_camelcase::FuncParamNameCamelcase;
use crate::rules::naming::func_visibility::FuncVisibility;
use crate::rules::naming::use_forbidden_name::UseForbiddenName;
use crate::rules::naming::var_name_mixedcase::VarNameMixedCase;
use crate::rules::types::{RuleEntry, RulesMap};
use crate::rules::RuleBuilder;
use std::collections::HashMap;
Expand All @@ -17,6 +18,7 @@ pub(crate) mod event_name_camelcase;
pub(crate) mod func_name_camelcase;
pub(crate) mod func_visibility;
pub(crate) mod use_forbidden_name;
pub(crate) mod var_name_mixedcase;

// List all rules

Expand All @@ -29,6 +31,7 @@ pub fn create_default_rules() -> Vec<RuleEntry> {
FuncVisibility::create_default(),
EventNameCamelCase::create_default(),
ConstNameSnakeCase::create_default(),
VarNameMixedCase::create_default(),
]
}

Expand Down Expand Up @@ -60,6 +63,10 @@ pub fn create_rules() -> RulesMap {
const_name_snakecase::RULE_ID.to_string(),
ConstNameSnakeCase::create,
);
rules.insert(
var_name_mixedcase::RULE_ID.to_string(),
VarNameMixedCase::create,
);

rules
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use ast_extractor::Spanned;

use crate::linter::SolidFile;
use crate::rules::types::*;
use crate::types::*;

pub const RULE_ID: &str = "var-name-mixedcase";
const MESSAGE: &str = "variable should be in MixedCase";

pub struct VarNameMixedCase {
data: RuleEntry,
}

impl VarNameMixedCase {
fn create_diag(
&self,
location: (ast_extractor::LineColumn, ast_extractor::LineColumn),
file: &SolidFile,
) -> LintDiag {
LintDiag {
id: RULE_ID.to_string(),
range: Range {
start: Position {
line: location.0.line,
character: location.0.column + 1,
},
end: Position {
line: location.1.line,
character: location.1.column,
},
},
message: MESSAGE.to_string(),
severity: Some(self.data.severity),
code: None,
source: None,
uri: file.path.clone(),
source_file_content: file.content.clone(),
}
}
}

impl RuleType for VarNameMixedCase {
fn diagnose(&self, file: &SolidFile, _files: &[SolidFile]) -> Vec<LintDiag> {
let mut res = Vec::new();

let variables_definition =
ast_extractor::retriever::retrieve_variable_definition_nodes(&file.data);
for variable in variables_definition {
if variable.name.to_string()[1..].find('_').is_some() {
let span = variable.name.span();
res.push(self.create_diag((span.start(), span.end()), file));
}
}

let variables_declaration =
ast_extractor::retriever::retrieve_variable_declaration_nodes(&file.data);
for variable in variables_declaration {
if variable.name.is_some() {
let name = variable.name.unwrap();
if name.to_string()[1..].find('_').is_some() {
let span = name.span();
res.push(self.create_diag((span.start(), span.end()), file));
}
}
}
res
}
}

impl VarNameMixedCase {
pub(crate) fn create(data: RuleEntry) -> Box<dyn RuleType> {
let rule = VarNameMixedCase { data };
Box::new(rule)
}

pub(crate) fn create_default() -> RuleEntry {
RuleEntry {
id: RULE_ID.to_string(),
severity: Severity::WARNING,
data: vec![],
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "solidhunter",
"includes": [],
"plugins": [],
"rules": [
{
"id": "var-name-mixedcase",
"severity": "WARNING",
"data": []
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pragma solidity ^0.8.0;

contract Test {
uint256 contracts = 0; // Valid
uint256 _contract2 = 0; // Valid
uint256 testContractForLinter = 0; // Valid
uint256 test_contract_for_linter = 0; // Not Valid

function test() public pure returns (string memory) {
uint256 test = 0; // Valid
uint256 _test2 = 0; // Valid
uint256 testForLinter = 0; // Valid
uint256 test_for_linter = 0; // Not Valid
return "TEST";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var-name-mixedcase:7:13:7:36
var-name-mixedcase:13:17:13:31
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,6 @@ test_directories! {
ImplicitTypes,
PayableFallback,
VisibilityModifierOrder,
VarNameMixedCase,
GlobalImport
}