From 46fa713c29f171ef1326e538c2bd3ba7c7c0ab8f Mon Sep 17 00:00:00 2001 From: Daniel Ramos Date: Fri, 7 Jul 2023 15:09:58 -0700 Subject: [PATCH 1/4] Add playground tests to CI (#534) * Add playground to CI * Skip test that doesnt run on CI because of multiprocessing * Skip test that doesnt work in CI --- .github/workflows/playground_test.yml | 30 +++++++++++++++++++ .../rule_inference/rule_application.py | 5 ---- .../tests/test_codebase_refactorer.py | 19 +++++++----- 3 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/playground_test.yml diff --git a/.github/workflows/playground_test.yml b/.github/workflows/playground_test.yml new file mode 100644 index 000000000..951cc2836 --- /dev/null +++ b/.github/workflows/playground_test.yml @@ -0,0 +1,30 @@ +name: Playground Piranha +on: + pull_request: + push: + branches: + - master +jobs: + detect: + uses: ./.github/workflows/detect_changes.yml + + build_and_test: + name: Playground test + runs-on: ubuntu-latest + needs: detect + steps: + - name: Checkout Piranha sources + uses: actions/checkout@v3 + - name: Set up Python 3.9 + uses: actions/setup-python@v4 + with: + python-version: 3.9 + - name: Create virtualenv and install dependencies + run: | + python -m venv .env + source .env/bin/activate + pip3 install -r experimental/requirements.txt + - name: Run Python tests + run: | + source .env/bin/activate + pytest -s -rx . diff --git a/experimental/piranha_playground/rule_inference/rule_application.py b/experimental/piranha_playground/rule_inference/rule_application.py index a89b139ab..8f4c2f445 100644 --- a/experimental/piranha_playground/rule_inference/rule_application.py +++ b/experimental/piranha_playground/rule_inference/rule_application.py @@ -133,10 +133,6 @@ def refactor_codebase(self, dry_run: bool = True) -> List[PiranhaOutputSummary]: try: toml_dict = toml.loads(self.rules) rule_graph = RawRuleGraph.from_toml(toml_dict) - - # Create the Piranha rule graph - - # Create the PiranhaArguments object args = PiranhaArguments( language=self.language, path_to_codebase=self.path_to_codebase, @@ -169,7 +165,6 @@ def refactor_snippet(source_code: str, language: str, rules: str) -> str: try: toml_dict = toml.loads(rules) substitutions = toml_dict.get("substitutions", [{}])[0] - refactored_code, success = run_piranha_with_timeout( source_code, language, diff --git a/experimental/piranha_playground/rule_inference/tests/test_codebase_refactorer.py b/experimental/piranha_playground/rule_inference/tests/test_codebase_refactorer.py index 3c102ba55..a88cb58c6 100644 --- a/experimental/piranha_playground/rule_inference/tests/test_codebase_refactorer.py +++ b/experimental/piranha_playground/rule_inference/tests/test_codebase_refactorer.py @@ -57,17 +57,20 @@ def test_run_piranha_with_timeout_success(): assert rewrite.p_match.matched_string and rewrite.p_match.matches -# Test for timeout scenario while executing Piranha -def test_run_piranha_with_timeout_exception(): +@pytest.mark.skip(reason="This test doesn't work in CI") +def test_snippet_application(): language = "java" - graph = """ + graph = ''' [[rules]] name = "rename_variable" - query = "(identifier) @var_name" + query = """( + (identifier) @var_name + (#eq? @var_name "A") + )""" replace_node = "var_name" - replace = "other_name" - """ + replace = "B" + ''' source_code = "class A {}" - with pytest.raises(CodebaseRefactorerException): - CodebaseRefactorer.refactor_snippet(source_code, language, graph) + x = CodebaseRefactorer.refactor_snippet(source_code, language, graph) + assert x == "class B {}" From e0064628530df317e2096e7700181cd18aac5f2f Mon Sep 17 00:00:00 2001 From: Ameya Ketkar <94497232+ketkarameya@users.noreply.github.com> Date: Sun, 9 Jul 2023 15:41:34 -0700 Subject: [PATCH 2/4] Introduce CompiledCGPatterns capturing the TS-Query and regex (placeholder) ghstack-source-id: 0ef1c1ae7eaf0b3c2d49a0287818b1b2677b33a0 Pull Request resolved: https://github.com/uber/piranha/pull/527 --- src/models/capture_group_patterns.rs | 55 ++++++++++++++++++- src/models/filter.rs | 21 ++----- src/models/matches.rs | 10 ++-- src/models/rule_store.rs | 20 ++++--- src/models/scopes.rs | 9 +-- src/models/source_code_unit.rs | 12 +--- .../unit_tests/rule_graph_validation_test.rs | 10 ++++ src/utilities/tree_sitter_utilities.rs | 22 -------- 8 files changed, 90 insertions(+), 69 deletions(-) diff --git a/src/models/capture_group_patterns.rs b/src/models/capture_group_patterns.rs index 9ac618a4a..1929d6bee 100644 --- a/src/models/capture_group_patterns.rs +++ b/src/models/capture_group_patterns.rs @@ -14,13 +14,17 @@ Copyright (c) 2023 Uber Technologies, Inc. use crate::{ models::Validator, utilities::{ - tree_sitter_utilities::{get_ts_query_parser, number_of_errors}, + tree_sitter_utilities::{get_all_matches_for_query, get_ts_query_parser, number_of_errors}, Instantiate, }, }; use pyo3::prelude::pyclass; +use regex::Regex; use serde_derive::Deserialize; use std::collections::HashMap; +use tree_sitter::{Node, Query}; + +use super::matches::Match; #[pyclass] #[derive(Deserialize, Debug, Clone, Default, PartialEq, Hash, Eq)] @@ -38,12 +42,18 @@ impl CGPattern { impl Validator for CGPattern { fn validate(&self) -> Result<(), String> { + if self.pattern().starts_with("rgx ") { + panic!("Regex not supported") + } let mut parser = get_ts_query_parser(); parser .parse(self.pattern(), None) .filter(|x| number_of_errors(&x.root_node()) == 0) .map(|_| Ok(())) - .unwrap_or(Err(format!("Cannot parse - {}", self.pattern()))) + .unwrap_or(Err(format!( + "Cannot parse the tree-sitter query - {}", + self.pattern() + ))) } } @@ -56,3 +66,44 @@ impl Instantiate for CGPattern { CGPattern::new(self.pattern().instantiate(&substitutions)) } } + +#[derive(Debug)] +pub(crate) enum CompiledCGPattern { + Q(Query), + R(Regex), // Regex is not yet supported +} + +impl CompiledCGPattern { + /// Applies the CGPattern (self) upon the input `node`, and returns the first match + /// # Arguments + /// * `node` - the root node to apply the query upon + /// * `source_code` - the corresponding source code string for the node. + /// * `recursive` - if `true` it matches the query to `self` and `self`'s sub-ASTs, else it matches the `query` only to `self`. + pub(crate) fn get_match(&self, node: &Node, source_code: &str, recursive: bool) -> Option { + if let Some(m) = self + .get_matches(node, source_code.to_string(), recursive, None, None) + .first() + { + return Some(m.clone()); + } + None + } + + /// Applies the pattern upon the given `node`, and gets all the matches + pub(crate) fn get_matches( + &self, node: &Node, source_code: String, recursive: bool, replace_node: Option, + replace_node_idx: Option, + ) -> Vec { + match self { + CompiledCGPattern::Q(query) => get_all_matches_for_query( + node, + source_code, + query, + recursive, + replace_node, + replace_node_idx, + ), + CompiledCGPattern::R(_) => panic!("Regex is not yet supported!!!"), + } + } +} diff --git a/src/models/filter.rs b/src/models/filter.rs index 962df6ebd..f8ebbcf41 100644 --- a/src/models/filter.rs +++ b/src/models/filter.rs @@ -22,10 +22,7 @@ use pyo3::prelude::{pyclass, pymethods}; use serde_derive::Deserialize; use tree_sitter::Node; -use crate::utilities::{ - gen_py_str_methods, - tree_sitter_utilities::{get_all_matches_for_query, get_match_for_query, get_node_for_range}, -}; +use crate::utilities::{gen_py_str_methods, tree_sitter_utilities::get_node_for_range}; use super::{ capture_group_patterns::CGPattern, default_configs::default_child_count, @@ -415,9 +412,8 @@ impl SourceCodeUnit { } while let Some(parent) = current_node.parent() { - if let Some(p_match) = - get_match_for_query(&parent, self.code(), rule_store.query(ts_query), false) - { + let pattern = rule_store.query(ts_query); + if let Some(p_match) = pattern.get_match(&parent, self.code(), false) { let matched_ancestor = get_node_for_range( self.root_node(), p_match.range().start_byte, @@ -442,14 +438,7 @@ impl SourceCodeUnit { // Retrieve all matches within the ancestor node let contains_query = &rule_store.query(filter.contains()); - let matches = get_all_matches_for_query( - ancestor, - self.code().to_string(), - contains_query, - true, - None, - None, - ); + let matches = contains_query.get_matches(ancestor, self.code().to_string(), true, None, None); let at_least = filter.at_least as usize; let at_most = filter.at_most as usize; // Validate if the count of matches falls within the expected range @@ -464,7 +453,7 @@ impl SourceCodeUnit { // Check if there's a match within the scope node // If one of the filters is not satisfied, return false let query = &rule_store.query(ts_query); - if get_match_for_query(ancestor, self.code(), query, true).is_some() { + if query.get_match(ancestor, self.code(), true).is_some() { return false; } } diff --git a/src/models/matches.rs b/src/models/matches.rs index bf77cb95f..202ce8ac5 100644 --- a/src/models/matches.rs +++ b/src/models/matches.rs @@ -20,10 +20,7 @@ use pyo3::prelude::{pyclass, pymethods}; use serde_derive::{Deserialize, Serialize}; use tree_sitter::Node; -use crate::utilities::{ - gen_py_str_methods, - tree_sitter_utilities::{get_all_matches_for_query, get_node_for_range}, -}; +use crate::utilities::{gen_py_str_methods, tree_sitter_utilities::get_node_for_range}; use super::{ piranha_arguments::PiranhaArguments, rule::InstantiatedRule, rule_store::RuleStore, @@ -291,10 +288,11 @@ impl SourceCodeUnit { } else { (rule.replace_node(), rule.replace_idx()) }; - let mut all_query_matches = get_all_matches_for_query( + + let pattern = rule_store.query(&rule.query()); + let mut all_query_matches = pattern.get_matches( &node, self.code().to_string(), - rule_store.query(&rule.query()), recursive, replace_node_tag, replace_node_idx, diff --git a/src/models/rule_store.rs b/src/models/rule_store.rs index fe239da8c..d91780fc9 100644 --- a/src/models/rule_store.rs +++ b/src/models/rule_store.rs @@ -22,21 +22,22 @@ use itertools::Itertools; use jwalk::WalkDir; use log::{debug, trace}; use regex::Regex; -use tree_sitter::Query; use crate::{ models::capture_group_patterns::CGPattern, models::piranha_arguments::PiranhaArguments, models::scopes::ScopeQueryGenerator, utilities::read_file, }; -use super::{language::PiranhaLanguage, rule::InstantiatedRule}; +use super::{ + capture_group_patterns::CompiledCGPattern, language::PiranhaLanguage, rule::InstantiatedRule, +}; use glob::Pattern; /// This maintains the state for Piranha. #[derive(Debug, Getters, Default)] pub(crate) struct RuleStore { // Caches the compiled tree-sitter queries. - rule_query_cache: HashMap, + rule_query_cache: HashMap, // Current global rules to be applied. #[get = "pub"] global_rules: Vec, @@ -75,11 +76,16 @@ impl RuleStore { /// Get the compiled query for the `query_str` from the cache /// else compile it, add it to the cache and return it. - pub(crate) fn query(&mut self, query_str: &CGPattern) -> &Query { - self + pub(crate) fn query(&mut self, cg_pattern: &CGPattern) -> &CompiledCGPattern { + let pattern = cg_pattern.pattern(); + if pattern.starts_with("rgx ") { + panic!("Regex not supported.") + } + + &*self .rule_query_cache - .entry(query_str.pattern()) - .or_insert_with(|| self.language.create_query(query_str.pattern())) + .entry(pattern.to_string()) + .or_insert_with(|| CompiledCGPattern::Q(self.language.create_query(pattern))) } // For the given scope level, get the ScopeQueryGenerator from the `scope_config.toml` file diff --git a/src/models/scopes.rs b/src/models/scopes.rs index c494f7435..7393d1776 100644 --- a/src/models/scopes.rs +++ b/src/models/scopes.rs @@ -13,7 +13,6 @@ Copyright (c) 2023 Uber Technologies, Inc. use super::capture_group_patterns::CGPattern; use super::{rule_store::RuleStore, source_code_unit::SourceCodeUnit}; -use crate::utilities::tree_sitter_utilities::get_match_for_query; use crate::utilities::tree_sitter_utilities::get_node_for_range; use crate::utilities::Instantiate; use derive_builder::Builder; @@ -65,12 +64,8 @@ impl SourceCodeUnit { changed_node.kind() ); for m in &scope_enclosing_nodes { - if let Some(p_match) = get_match_for_query( - &changed_node, - self.code(), - rules_store.query(m.enclosing_node()), - false, - ) { + let pattern = rules_store.query(m.enclosing_node()); + if let Some(p_match) = pattern.get_match(&changed_node, self.code(), false) { // Generate the scope query for the specific context by substituting the // the tags with code snippets appropriately in the `generator` query. return m.scope().instantiate(p_match.matches()); diff --git a/src/models/source_code_unit.rs b/src/models/source_code_unit.rs index 93230262a..71c173e07 100644 --- a/src/models/source_code_unit.rs +++ b/src/models/source_code_unit.rs @@ -25,8 +25,7 @@ use crate::{ models::capture_group_patterns::CGPattern, models::rule_graph::{GLOBAL, PARENT}, utilities::tree_sitter_utilities::{ - get_match_for_query, get_node_for_range, get_replace_range, get_tree_sitter_edit, - number_of_errors, + get_node_for_range, get_replace_range, get_tree_sitter_edit, number_of_errors, }, }; @@ -299,13 +298,8 @@ impl SourceCodeUnit { // let mut scope_node = self.root_node(); if let Some(query_str) = scope_query { // Apply the scope query in the source code and get the appropriate node - let tree_sitter_scope_query = rules_store.query(query_str); - if let Some(p_match) = get_match_for_query( - &self.root_node(), - self.code(), - tree_sitter_scope_query, - true, - ) { + let scope_pattern = rules_store.query(query_str); + if let Some(p_match) = scope_pattern.get_match(&self.root_node(), self.code(), true) { return get_node_for_range( self.root_node(), p_match.range().start_byte, diff --git a/src/models/unit_tests/rule_graph_validation_test.rs b/src/models/unit_tests/rule_graph_validation_test.rs index 9102ff837..f12d9880a 100644 --- a/src/models/unit_tests/rule_graph_validation_test.rs +++ b/src/models/unit_tests/rule_graph_validation_test.rs @@ -118,3 +118,13 @@ fn test_filter_bad_arg_contains_n_sibling() { .sibling_count(2) .build(); } + +#[test] +#[should_panic(expected = "Regex not supported")] +fn test_unsupported_regex() { + RuleGraphBuilder::default() + .rules(vec![ + piranha_rule! {name = "Test rule", query = "rgx (\\w+) (\\w)+"}, + ]) + .build(); +} diff --git a/src/utilities/tree_sitter_utilities.rs b/src/utilities/tree_sitter_utilities.rs index 97ef334a3..6cbd5832b 100644 --- a/src/utilities/tree_sitter_utilities.rs +++ b/src/utilities/tree_sitter_utilities.rs @@ -25,28 +25,6 @@ use std::collections::HashMap; use tree_sitter::{InputEdit, Node, Parser, Point, Query, QueryCapture, QueryCursor, Range}; use tree_sitter_traversal::{traverse, Order}; -/// Applies the query upon the given node, and gets all the matches -/// # Arguments -/// * `node` - the root node to apply the query upon -/// * `source_code` - the corresponding source code string for the node. -/// * `query` - the query to be applied -/// * `recursive` - if `true` it matches the query to `self` and `self`'s sub-ASTs, else it matches the `query` only to `self`. -/// -/// # Returns -/// A vector of `tuples` containing the range of the matches in the source code and the corresponding mapping for the tags (to code snippets). -/// By default it returns the range of the outermost node for each query match. -/// If `replace_node` is provided in the rule, it returns the range of the node corresponding to that tag. -pub(crate) fn get_match_for_query( - node: &Node, source_code: &str, query: &Query, recursive: bool, -) -> Option { - if let Some(m) = - get_all_matches_for_query(node, source_code.to_string(), query, recursive, None, None).first() - { - return Some(m.clone()); - } - None -} - /// Applies the query upon the given `node`, and gets the first match /// # Arguments /// * `node` - the root node to apply the query upon From ccb20f7ffba8808d55dc9ed11cd6373fff64b4ce Mon Sep 17 00:00:00 2001 From: Ameya Ketkar <94497232+ketkarameya@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:47:30 -0700 Subject: [PATCH 3/4] Aggressively simplify conjunction where RHS is false (#532) --- src/cleanup_rules/go/rules.toml | 11 +---------- src/cleanup_rules/java/rules.toml | 11 +++-------- src/cleanup_rules/kt/rules.toml | 4 +--- src/cleanup_rules/swift/rules.toml | 4 ++-- .../boolean_expression_simplify/expected/sample.go | 13 ++++--------- .../boolean_expression_simplify/input/sample.go | 6 +++--- .../control/expected/XPMethodChainCases.java | 4 ---- .../control/expected/XPMethodChainCases.kt | 3 --- .../swift/cleanup_rules/expected/SampleClass.swift | 2 +- 9 files changed, 15 insertions(+), 43 deletions(-) diff --git a/src/cleanup_rules/go/rules.toml b/src/cleanup_rules/go/rules.toml index b3be2d1d2..590734c72 100644 --- a/src/cleanup_rules/go/rules.toml +++ b/src/cleanup_rules/go/rules.toml @@ -129,16 +129,7 @@ name = "simplify_something_and_false" query = """ ( (binary_expression - left : ([ - (identifier) - (parenthesized_expression (identifier)) - (true) - (parenthesized_expression (true)) - (false) - (parenthesized_expression (false)) - (selector_expression) - (parenthesized_expression (selector_expression)) - ]) @lhs + left : (_) @lhs operator : "&&" right: [(false) (parenthesized_expression (false))] ) @binary_expression diff --git a/src/cleanup_rules/java/rules.toml b/src/cleanup_rules/java/rules.toml index 9039ed40d..1e9ddf5a1 100755 --- a/src/cleanup_rules/java/rules.toml +++ b/src/cleanup_rules/java/rules.toml @@ -219,15 +219,10 @@ groups = ["boolean_expression_simplify"] query = """ ( (binary_expression - left : [ - (identifier) - (true) - (false) - ] @lhs + left : (_) @lhs operator : "&&" - right: (false) - ) -@binary_expression) + right: (false)) @binary_expression +) """ replace = "false" replace_node = "binary_expression" diff --git a/src/cleanup_rules/kt/rules.toml b/src/cleanup_rules/kt/rules.toml index ae68a6ce5..1c942fc92 100755 --- a/src/cleanup_rules/kt/rules.toml +++ b/src/cleanup_rules/kt/rules.toml @@ -288,9 +288,7 @@ groups = ["boolean_expression_simplify"] name = "simplify_something_and_false" query = """ ( -(conjunction_expression [(simple_identifier) - (boolean_literal) - ] @lhs +(conjunction_expression (_) @lhs ((boolean_literal) @rhs) ) @conjunction_expression (#eq? @rhs "false") ) diff --git a/src/cleanup_rules/swift/rules.toml b/src/cleanup_rules/swift/rules.toml index 78684925b..268803def 100644 --- a/src/cleanup_rules/swift/rules.toml +++ b/src/cleanup_rules/swift/rules.toml @@ -194,10 +194,10 @@ is_seed_rule = false # In other scenarios (i.e. is a method invocation or some other expression) we would not simplify at all, as: # such expressions could have side effects [[rules]] -name = "some_identifier_and_false" +name = "something_and_false" query = """( (conjunction_expression - lhs: (simple_identifier) + lhs: (_) rhs: [(boolean_literal) @false (tuple_expression value: (boolean_literal) @false)] diff --git a/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/expected/sample.go b/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/expected/sample.go index 40fc1d0f2..812f8356a 100644 --- a/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/expected/sample.go +++ b/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/expected/sample.go @@ -53,17 +53,12 @@ func simplify_false_and_something(something bool) { fmt.Println("else 4") // selector_expression: simplify fmt.Println("else 5") - // does not simplify binary_expression; left call may contain side-effects - if exp.BoolValue("random") && false { - fmt.Println("keep 1") - } else { - fmt.Println("keep 2") - } + // simplify + + fmt.Println("keep 2") // function call && false - if f1() && false { - fmt.Println("keep as it is") - } + // function call || true if f1() || true { diff --git a/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/input/sample.go b/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/input/sample.go index cad0cdd94..2853e6eb3 100644 --- a/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/input/sample.go +++ b/test-resources/go/feature_flag/builtin_rules/boolean_expression_simplify/input/sample.go @@ -91,15 +91,15 @@ func simplify_false_and_something(something bool) { } else { fmt.Println("else 5") } - // does not simplify binary_expression; left call may contain side-effects + // simplify if exp.BoolValue("random") && exp.BoolValue("false") { - fmt.Println("keep 1") + fmt.Println("to be removed 1") } else { fmt.Println("keep 2") } // function call && false if f1() && exp.BoolValue("false") { - fmt.Println("keep as it is") + fmt.Println("to be removed 2") } // function call || true diff --git a/test-resources/java/feature_flag_system_2/control/expected/XPMethodChainCases.java b/test-resources/java/feature_flag_system_2/control/expected/XPMethodChainCases.java index b503ba295..71076e8f8 100644 --- a/test-resources/java/feature_flag_system_2/control/expected/XPMethodChainCases.java +++ b/test-resources/java/feature_flag_system_2/control/expected/XPMethodChainCases.java @@ -33,10 +33,6 @@ public static void foobar(Parameter cp) { System.out.println("!!!"); } - if (sp.otherFlag().getCachedValue() && false) { - System.out.println("!!!"); - } - if (sp.otherFlag().getCachedValue()) { System.out.println("!!!"); } diff --git a/test-resources/kt/feature_flag_system_2/control/expected/XPMethodChainCases.kt b/test-resources/kt/feature_flag_system_2/control/expected/XPMethodChainCases.kt index 0d9519803..595c87454 100644 --- a/test-resources/kt/feature_flag_system_2/control/expected/XPMethodChainCases.kt +++ b/test-resources/kt/feature_flag_system_2/control/expected/XPMethodChainCases.kt @@ -37,9 +37,6 @@ internal class XPMethodChainCases { println("!!!") } - if (sp.isOtherFlag().cachedValue && false) { - println("LHS is not a simple identifier!!!") - } if (sp.isOtherFlag().cachedValue) { println("!!!") } diff --git a/test-resources/swift/cleanup_rules/expected/SampleClass.swift b/test-resources/swift/cleanup_rules/expected/SampleClass.swift index 53001cdf2..844ca0d41 100644 --- a/test-resources/swift/cleanup_rules/expected/SampleClass.swift +++ b/test-resources/swift/cleanup_rules/expected/SampleClass.swift @@ -43,7 +43,7 @@ class SampleClass { func checkAndFalse() { isEnabled = false isEnabled = false - isEnabled = f2() && false + isEnabled = false isEnabled = false } From 6fed6710dd205a433fe4726a5bd82fade372a7ab Mon Sep 17 00:00:00 2001 From: Blake Shaw Date: Mon, 10 Jul 2023 16:57:40 -0400 Subject: [PATCH 4/4] Update POLYGLOT_README.md (#535) Parameter repeated typo Co-authored-by: Ameya Ketkar <94497232+ketkarameya@users.noreply.github.com> --- POLYGLOT_README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/POLYGLOT_README.md b/POLYGLOT_README.md index 9776d13fb..c68a65c0b 100644 --- a/POLYGLOT_README.md +++ b/POLYGLOT_README.md @@ -145,7 +145,6 @@ An object of PiranhaArguments can be instantiated with the following arguments: - (*optional*) `number_of_ancestors_in_parent_scope` (`usize`): The number of ancestors considered when `PARENT` rules - (*optional*) `delete_file_if_empty` (`bool`): User option that determines whether an empty file will be deleted - (*optional*) `delete_consecutive_new_lines` (`bool`) : Replaces consecutive `\n`s with a single `\n` -- (*optional*) `dry_run` (`bool`) : Disables in-place rewriting of code
Returns