-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validate Rule graph #493
Validate Rule graph #493
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,6 @@ use std::{collections::HashMap, fs::File, io::Write, path::PathBuf}; | |
|
||
use itertools::Itertools; | ||
use log::{debug, info}; | ||
use tree_sitter::Parser; | ||
|
||
use crate::models::rule_store::RuleStore; | ||
|
||
|
@@ -111,11 +110,9 @@ impl Piranha { | |
/// Performs cleanup related to stale flags | ||
fn perform_cleanup(&mut self) { | ||
// Setup the parser for the specific language | ||
let mut parser = Parser::new(); | ||
let piranha_args = &self.piranha_arguments; | ||
parser | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. un related to this PR :| , but I observed that i was not using the |
||
.set_language(*piranha_args.language().language()) | ||
.expect("Could not set the language for the parser."); | ||
|
||
let mut parser = piranha_args.language().parser(); | ||
|
||
let mut path_to_codebase = self.piranha_arguments.path_to_codebase().to_string(); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,9 @@ use crate::utilities::{ | |
tree_sitter_utilities::{get_all_matches_for_query, get_match_for_query, get_node_for_range}, | ||
}; | ||
|
||
use super::{rule::InstantiatedRule, rule_store::RuleStore, source_code_unit::SourceCodeUnit}; | ||
use super::{ | ||
rule::InstantiatedRule, rule_store::RuleStore, source_code_unit::SourceCodeUnit, Validator, | ||
}; | ||
|
||
use crate::utilities::{tree_sitter_utilities::TSQuery, Instantiate}; | ||
|
||
|
@@ -103,47 +105,68 @@ impl Filter { | |
gen_py_str_methods!(); | ||
} | ||
|
||
impl FilterBuilder { | ||
/// Builds Filter from FilterBuilder | ||
/// * create Filter from the builder | ||
/// * validates new argument combinations | ||
pub fn build(&self) -> Filter { | ||
match &self._validate() { | ||
Ok(filter) => filter.clone(), | ||
Err(e) => panic!("Invalid filter - {}", e), | ||
} | ||
} | ||
|
||
fn _validate(&self) -> Result<Filter, String> { | ||
let _filter: Filter = self.create().unwrap(); | ||
|
||
impl Validator for Filter { | ||
fn validate(&self) -> Result<(), String> { | ||
// Only allow users to set either contains or not_contains, but not both | ||
if !_filter.contains().get_query().is_empty() && !_filter.not_contains().is_empty() { | ||
if *self.contains() != default_contains_query() | ||
&& *self.not_contains() != default_not_contains_queries() | ||
{ | ||
return Err( | ||
"Invalid Filter Argument. `contains` and `not_contains` cannot be set at the same time !!! Please use two filters instead." | ||
.to_string(), | ||
); | ||
} | ||
|
||
if _filter.at_least > _filter.at_most { | ||
if self.at_least > self.at_most { | ||
return Err( | ||
"Invalid Filter Argument. `at_least` should be less than or equal to `at_most` !!!" | ||
.to_string(), | ||
); | ||
} | ||
|
||
// If the user set `at_least` or `at_most`, then the contains query cannot be empty | ||
if (_filter.at_least != default_contains_at_least() | ||
|| _filter.at_most != default_contains_at_most()) | ||
&& _filter.contains().get_query().is_empty() | ||
if (self.at_least != default_contains_at_least() || self.at_most != default_contains_at_most()) | ||
&& self.contains().get_query().is_empty() | ||
{ | ||
return Err( | ||
"Invalid Filter Argument. `at_least` or `at_most` is set, but `contains` is empty !!!" | ||
.to_string(), | ||
); | ||
} | ||
|
||
Ok(_filter) | ||
if *self.enclosing_node() != default_enclosing_node() { | ||
self.enclosing_node().validate()? | ||
} | ||
|
||
if *self.not_enclosing_node() != default_not_enclosing_node() { | ||
self.not_enclosing_node().validate()? | ||
} | ||
|
||
if *self.contains() != default_contains_query() { | ||
self.contains().validate()? | ||
} | ||
|
||
if *self.not_contains() != default_not_contains_queries() { | ||
self.not_contains().iter().try_for_each(|x| x.validate())? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Such ergonomic APIs make me like Rust :) ( |
||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl FilterBuilder { | ||
/// Builds Filter from FilterBuilder | ||
/// * create Filter from the builder | ||
/// * validates new argument combinations | ||
pub fn build(&self) -> Filter { | ||
match &self._validate() { | ||
Ok(filter) => filter.clone(), | ||
Err(e) => panic!("Invalid filter - {}", e), | ||
} | ||
} | ||
|
||
fn _validate(&self) -> Result<Filter, String> { | ||
let _filter: Filter = self.create().unwrap(); | ||
_filter.validate().map(|_| _filter) | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,3 +24,7 @@ pub(crate) mod rule_graph; | |
pub(crate) mod rule_store; | ||
pub(crate) mod scopes; | ||
pub(crate) mod source_code_unit; | ||
|
||
pub(crate) trait Validator { | ||
fn validate(&self) -> Result<(), String>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as our validation enriches, I will modify this Type parameter |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,20 +11,21 @@ Copyright (c) 2023 Uber Technologies, Inc. | |
limitations under the License. | ||
*/ | ||
|
||
use derive_builder::Builder; | ||
use getset::{Getters, MutGetters}; | ||
use itertools::Itertools; | ||
|
||
use crate::{ | ||
models::{outgoing_edges::OutgoingEdges, rule::Rule}, | ||
utilities::{gen_py_str_methods, read_toml, MapOfVec}, | ||
}; | ||
use colored::Colorize; | ||
use derive_builder::Builder; | ||
use getset::{Getters, MutGetters}; | ||
use itertools::Itertools; | ||
use std::{collections::HashMap, path::Path}; | ||
|
||
use super::{ | ||
default_configs::{default_edges, default_rule_graph_map, default_rules}, | ||
outgoing_edges::Edges, | ||
rule::{InstantiatedRule, Rules}, | ||
Validator, | ||
}; | ||
use pyo3::prelude::{pyclass, pymethods}; | ||
|
||
|
@@ -54,6 +55,15 @@ pub struct RuleGraph { | |
graph: HashMap<String, Vec<(String, String)>>, | ||
} | ||
|
||
impl Validator for RuleGraph { | ||
fn validate(&self) -> Result<(), String> { | ||
match self.rules().iter().try_for_each(|rule| rule.validate()) { | ||
Ok(()) => Ok(()), | ||
Err(e) => Err(format!("Incorrect Rule Graph - {}", e)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Do we report the first failing rule or all syntax errors in every rule in the rule graph? (Neither would be right or wrong, specially at this point, just want to make sure. I'd think it's the first case looking at this, but nor sure what the semantics of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are short-circuiting at the first exception. Thinking about it, I should eventually accumulate these errors and report them. |
||
} | ||
} | ||
} | ||
|
||
#[pymethods] | ||
impl RuleGraph { | ||
#[new] | ||
|
@@ -92,12 +102,18 @@ impl RuleGraphBuilder { | |
} | ||
} | ||
|
||
RuleGraphBuilder::default() | ||
let graph = RuleGraphBuilder::default() | ||
.edges(_rule_graph.edges().clone()) | ||
.rules(_rule_graph.rules().clone()) | ||
.graph(graph) | ||
.create() | ||
.unwrap() | ||
.unwrap(); | ||
|
||
if let Err(err) = graph.validate() { | ||
panic!("{}", err.as_str().red()); | ||
} | ||
|
||
graph | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found this bug (and the one below) :)