From b89b58485d4a0e2d3c7ddecf0cb7055c78183832 Mon Sep 17 00:00:00 2001 From: takeokunn Date: Mon, 24 Aug 2026 14:44:05 +0900 Subject: [PATCH 1/4] perf(cli): parallelize multi-file report commands across all cores Migrate ~257 CLI report commands from a serial per-file read/parse/analyze loop to the shared analyze_files/analyze_files_raw helper in packages/core/cli/src/shared.rs, which schedules work across all cores via std::thread::scope with a work-stealing atomic cursor (largest-file-first claim order), falling back to a serial iterator below an 8-file threshold. lint-* crates' report builders return LintError, and the package crate's return PackageRefactorError, neither of which implements From by design (an intentional one-way layering boundary: core crates must not depend on the CLI error type). Those ~245 files use analyze_files_raw, whose closure owns its own read and converts errors via the existing one-way From impl, instead of weakening that boundary. --- Cargo.lock | 1 + packages/core/cli/src/report/budget.rs | 29 ++- packages/core/cli/src/report/graph.rs | 10 +- packages/core/cli/src/report/render.rs | 3 +- packages/core/cli/src/shared.rs | 103 ++++++++++ packages/core/lint-engine/src/suppression.rs | 32 ++- packages/core/syntax/src/sexpr/edit.rs | 2 +- .../core/syntax/src/sexpr/formatter/core.rs | 13 +- packages/core/syntax/src/sexpr/navigation.rs | 8 + packages/core/syntax/src/sexpr/parser.rs | 2 - packages/core/syntax/src/sexpr/tree.rs | 15 +- packages/core/workspace/Cargo.toml | 1 + .../core/workspace/src/workspace/cache.rs | 111 +++++++--- .../core/workspace/src/workspace/discovery.rs | 3 + .../shadowed_binding_report/cli/workflow.rs | 20 +- .../src/cohesion_report/cli/workflow.rs | 17 +- .../src/debt_score_report/cli/workflow.rs | 17 +- .../src/docstring_report/cli/workflow.rs | 17 +- .../duplication_ratio_report/cli/workflow.rs | 17 +- .../src/hotspot_report/cli/workflow.rs | 17 +- .../src/indentation_report/cli/workflow.rs | 17 +- .../src/line_metrics_report/cli/workflow.rs | 17 +- .../src/todo_report/cli/workflow.rs | 17 +- .../src/data_check_report/cli/workflow.rs | 19 +- .../cli/workflow.rs | 191 ++++++++++++++---- .../unused_parameter_report/cli/workflow.rs | 20 +- .../src/generate_defsystem/cli/workflow.rs | 41 +++- .../src/generate_tests/cli/workflow.rs | 45 ++++- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../stringly_typed_dispatch/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../def_inside_function_body/cli/workflow.rs | 17 +- .../single_key_nested_path/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../defconstant_non_eql_value/cli/workflow.rs | 19 +- .../eval_when_body_never_runs/cli/workflow.rs | 19 +- .../eval_when_execute_only/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/case_key_eql_pitfall/cli/workflow.rs | 17 +- .../src/case_nil_key/cli/workflow.rs | 17 +- .../src/cond_t_clause/cli/workflow.rs | 17 +- .../cond_to_case_candidate/cli/workflow.rs | 17 +- .../src/constant_if_test/cli/workflow.rs | 17 +- .../src/constant_when_test/cli/workflow.rs | 17 +- .../src/de_morgan/cli/workflow.rs | 17 +- .../src/dead_boolean_operand/cli/workflow.rs | 16 +- .../cli/workflow.rs | 18 +- .../src/duplicate_case_keys/cli/workflow.rs | 16 +- .../src/duplicate_cond_tests/cli/workflow.rs | 16 +- .../src/empty_body/cli/workflow.rs | 17 +- .../exhaustive_case_otherwise/cli/workflow.rs | 19 +- .../src/identical_if_branches/cli/workflow.rs | 16 +- .../src/if_arity/cli/workflow.rs | 17 +- .../src/if_not/cli/workflow.rs | 17 +- .../src/if_to_or/cli/workflow.rs | 17 +- .../src/if_to_unless/cli/workflow.rs | 17 +- .../src/malformed_case_clause/cli/workflow.rs | 17 +- .../src/malformed_cond_clause/cli/workflow.rs | 17 +- .../src/negated_comparison/cli/workflow.rs | 17 +- .../src/negated_if/cli/workflow.rs | 17 +- .../src/negated_when_unless/cli/workflow.rs | 17 +- .../src/nested_boolean/cli/workflow.rs | 17 +- .../nested_cond_flattenable/cli/workflow.rs | 17 +- .../src/nested_unless/cli/workflow.rs | 17 +- .../src/nested_when/cli/workflow.rs | 17 +- .../src/one_armed_if/cli/workflow.rs | 17 +- .../src/quoted_case_key/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/redundant_if_nil/cli/workflow.rs | 17 +- .../src/single_clause_cond/cli/workflow.rs | 17 +- .../single_operand_boolean/cli/workflow.rs | 17 +- .../src/typecase_nil_key/cli/workflow.rs | 17 +- .../unreachable_case_clause/cli/workflow.rs | 17 +- .../unreachable_cond_clause/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/binds_constant/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/eval_when_situation/cli/workflow.rs | 17 +- .../src/explicit_nil_return/cli/workflow.rs | 17 +- .../src/go_to_undefined_tag/cli/workflow.rs | 17 +- .../handler_case_no_clauses/cli/workflow.rs | 17 +- .../malformed_iteration_spec/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/nested_progn/cli/workflow.rs | 17 +- .../src/prog2_to_progn/cli/workflow.rs | 17 +- .../src/redundant_body_progn/cli/workflow.rs | 17 +- .../src/redundant_prog1/cli/workflow.rs | 17 +- .../src/redundant_progn/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../self_recursive_tail_call/cli/workflow.rs | 22 +- .../tagbody_unreachable_tag/cli/workflow.rs | 17 +- .../unwind_protect_no_cleanup/cli/workflow.rs | 19 +- .../src/butlast_default_count/cli/workflow.rs | 17 +- .../src/coerce_to_t/cli/workflow.rs | 17 +- .../src/defpackage_quoted/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/duplicate_keyword/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../duplicate_let_bindings/cli/workflow.rs | 16 +- .../src/duplicate_parameters/cli/workflow.rs | 17 +- .../src/duplicate_setf_places/cli/workflow.rs | 17 +- .../src/empty_let/cli/workflow.rs | 17 +- .../flet_single_use_inlinable/cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/funcall_lambda/cli/workflow.rs | 17 +- .../src/getf_default_nil/cli/workflow.rs | 17 +- .../src/gethash_default/cli/workflow.rs | 17 +- .../giant_conditional_form/cli/workflow.rs | 22 +- .../lambda_list_keyword_order/cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/make_hash_table_test/cli/workflow.rs | 17 +- .../make_list_default_element/cli/workflow.rs | 19 +- .../src/malformed_let_binding/cli/workflow.rs | 17 +- .../src/manual_incf/cli/workflow.rs | 17 +- .../src/manual_push/cli/workflow.rs | 17 +- .../src/manual_pushnew/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/nested_char_case/cli/workflow.rs | 17 +- .../src/nested_cxr/cli/workflow.rs | 17 +- .../package_level_shadowing/cli/workflow.rs | 22 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/redundant_apply/cli/workflow.rs | 17 +- .../src/redundant_funcall/cli/workflow.rs | 17 +- .../src/redundant_identity/cli/workflow.rs | 17 +- .../src/redundant_let_star/cli/workflow.rs | 17 +- .../src/redundant_quote/cli/workflow.rs | 17 +- .../src/redundant_the/cli/workflow.rs | 17 +- .../src/self_assignment/cli/workflow.rs | 16 +- .../src/setf_arity/cli/workflow.rs | 16 +- .../src/setq_non_variable/cli/workflow.rs | 17 +- .../src/sharp_quoted_lambda/cli/workflow.rs | 17 +- .../src/single_value_bind/cli/workflow.rs | 17 +- .../src/the_arity/cli/workflow.rs | 17 +- .../src/typep_predicate/cli/workflow.rs | 17 +- .../src/values_list_of_list/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/eq_char_comparison/cli/workflow.rs | 17 +- .../src/eq_number_comparison/cli/workflow.rs | 16 +- .../src/eql_list_comparison/cli/workflow.rs | 17 +- .../src/eql_string_comparison/cli/workflow.rs | 16 +- .../src/equality_arity/cli/workflow.rs | 17 +- .../src/explicit_step_delta/cli/workflow.rs | 17 +- .../src/identity_arithmetic/cli/workflow.rs | 17 +- .../src/literal_place/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/modify_macro_arity/cli/workflow.rs | 17 +- .../src/negated_step_delta/cli/workflow.rs | 17 +- .../src/nil_comparison/cli/workflow.rs | 17 +- .../src/one_step_arithmetic/cli/workflow.rs | 17 +- .../src/redundant_divisor/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/self_comparison/cli/workflow.rs | 16 +- .../src/sign_comparison/cli/workflow.rs | 17 +- .../src/single_arg_comparison/cli/workflow.rs | 17 +- .../single_operand_arithmetic/cli/workflow.rs | 19 +- .../src/step_zero/cli/workflow.rs | 17 +- .../src/t_comparison/cli/workflow.rs | 17 +- .../src/verbose_negation/cli/workflow.rs | 17 +- .../src/zero_divisor/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../defclass_slot_shadowing/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/method_qualifier_typo/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../commented_repl_transcript/cli/workflow.rs | 24 ++- .../src/leftover_break_call/cli/workflow.rs | 23 ++- .../cli/workflow.rs | 24 ++- .../src/leftover_inspect_call/cli/workflow.rs | 24 ++- .../src/leftover_print_debug/cli/workflow.rs | 24 ++- .../src/leftover_step_call/cli/workflow.rs | 23 ++- .../cli/workflow.rs | 24 ++- .../src/leftover_trace_call/cli/workflow.rs | 23 ++- .../src/begin_single_form/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/memq_assq_literal_key/cli/workflow.rs | 17 +- .../named_let_never_recurs/cli/workflow.rs | 17 +- .../src/accessor_arity/cli/workflow.rs | 17 +- .../src/append_list_to_cons/cli/workflow.rs | 17 +- .../src/append_nil/cli/workflow.rs | 17 +- .../src/car_nthcdr/cli/workflow.rs | 17 +- .../src/car_reverse/cli/workflow.rs | 17 +- .../src/cons_to_list/cli/workflow.rs | 17 +- .../src/destructive_literal/cli/workflow.rs | 17 +- .../src/double_reverse/cli/workflow.rs | 17 +- .../src/eql_search_literal/cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../src/last_default_count/cli/workflow.rs | 17 +- .../src/list_star_nil/cli/workflow.rs | 17 +- .../src/list_star_to_cons/cli/workflow.rs | 17 +- .../src/nested_get_chain/cli/workflow.rs | 17 +- .../src/nth_constant_index/cli/workflow.rs | 17 +- .../src/nthcdr_small_index/cli/workflow.rs | 17 +- .../src/nthcdr_zero/cli/workflow.rs | 17 +- .../src/redundant_count_nil/cli/workflow.rs | 17 +- .../src/redundant_end_nil/cli/workflow.rs | 17 +- .../src/redundant_eql_test/cli/workflow.rs | 17 +- .../redundant_from_end_nil/cli/workflow.rs | 17 +- .../redundant_identity_key/cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../src/redundant_start_zero/cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../single_operand_list_op/cli/workflow.rs | 17 +- .../src/subseq_zero/cli/workflow.rs | 17 +- .../src/char_case_fold/cli/workflow.rs | 17 +- .../src/char_op_string/cli/workflow.rs | 17 +- .../src/code_char_char_code/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../cli/workflow.rs | 19 +- .../src/format_newline/cli/workflow.rs | 17 +- .../cli/workflow.rs | 19 +- .../src/format_to_string/cli/workflow.rs | 17 +- .../format_unknown_directive/cli/workflow.rs | 17 +- .../src/nested_string_case/cli/workflow.rs | 17 +- .../src/string_case_fold/cli/workflow.rs | 17 +- .../src/disabled_test_left_in/cli/workflow.rs | 17 +- .../src/duplicate_test_name/cli/workflow.rs | 17 +- .../src/empty_test_body/cli/workflow.rs | 17 +- .../src/sleep_in_test/cli/workflow.rs | 17 +- .../src/test_asserts_constant/cli/workflow.rs | 17 +- .../test_without_assertion/cli/workflow.rs | 17 +- .../circular_literal_report/cli/workflow.rs | 17 +- .../class_hierarchy_report/cli/workflow.rs | 17 +- .../duplicate_method_report/cli/workflow.rs | 14 +- .../src/duplicate_slot_report/cli/workflow.rs | 16 +- .../format_directive_report/cli/workflow.rs | 17 +- .../generic_dispatch_report/cli/workflow.rs | 17 +- .../src/loop_report/cli/workflow.rs | 17 +- .../macro_expansion_report/cli/workflow.rs | 17 +- .../src/macro_hygiene_report/cli/workflow.rs | 17 +- .../method_combination_report/cli/workflow.rs | 17 +- .../src/package_lock_report/cli/workflow.rs | 17 +- .../read_conditional_report/cli/workflow.rs | 17 +- .../src/read_time_eval_report/cli/workflow.rs | 17 +- .../src/readtable_case_report/cli/workflow.rs | 17 +- .../src/restart_report/cli/workflow.rs | 17 +- .../duplicate_export_report/cli/workflow.rs | 23 ++- .../feature/package/src/package/cli/report.rs | 24 +-- .../package_boundary_report/cli/workflow.rs | 16 +- .../package_conflict_report/cli/workflow.rs | 17 +- .../system_conflict_report/cli/workflow.rs | 17 +- .../src/unused_export_report/cli/workflow.rs | 24 ++- .../unused_nickname_report/cli/workflow.rs | 24 ++- .../src/unused_package_report/cli/workflow.rs | 24 ++- .../src/use_widening_report/cli/workflow.rs | 17 +- .../src/call_cycle_report/cli/workflow.rs | 20 +- .../src/call_graph_report/cli/workflow.rs | 20 +- .../src/call_report/cli/workflow.rs | 21 +- .../src/class_cycle_report/cli/workflow.rs | 15 +- .../src/complexity_report/cli/workflow.rs | 15 +- .../feature/project-analysis/src/error.rs | 9 + .../src/impact_report/cli/workflow.rs | 17 +- .../src/naming_report/cli/workflow.rs | 15 +- .../src/package_cycle_report/cli/workflow.rs | 15 +- .../src/reachability_report/cli/workflow.rs | 20 +- .../src/redefinition_report/cli/workflow.rs | 15 +- .../src/signature_report/cli/workflow.rs | 19 +- .../src/struct_cycle_report/cli/workflow.rs | 15 +- .../src/system_cycle_report/cli/workflow.rs | 16 +- .../undefined_package_report/cli/workflow.rs | 22 +- .../cli/workflow.rs | 19 +- .../src/api_diff_report/cli/workflow.rs | 17 +- .../src/api_surface_report/cli/workflow.rs | 17 +- .../src/blame_report/cli/workflow.rs | 17 +- .../external_system_report/cli/workflow.rs | 17 +- .../src/keyword_arity_report/cli/workflow.rs | 17 +- .../src/license_header_report/cli/workflow.rs | 17 +- .../src/license_report/cli/workflow.rs | 17 +- .../serial_consistency_report/cli/workflow.rs | 17 +- .../src/symbol_index_report/cli/workflow.rs | 17 +- .../src/symbol_report/cli/workflow.rs | 23 ++- .../src/test_map_report/cli/workflow.rs | 17 +- .../cli/workflow.rs | 17 +- .../src/refactor/cli/manifest/check.rs | 5 + .../src/refactor_checkpoint/cli/workflow.rs | 56 +++-- .../cli/remove_unused_definitions.rs | 56 ++--- .../src/definition_report/cli/workflow.rs | 51 ++--- .../src/definition_report/domain.rs | 69 +++---- .../domain/candidates.rs | 23 +-- .../domain/tests/mod.rs | 1 + .../domain/tests/validation.rs | 35 ++-- .../remove_unused_definition/domain/types.rs | 9 +- .../rename/domain/replace_call/call_site.rs | 4 +- .../src/rename/domain/replace_call/collect.rs | 13 +- .../src/rename/domain/wrap/call_site.rs | 4 +- .../rename/src/rename/domain/wrap/collect.rs | 4 +- .../src/constant_report/cli/workflow.rs | 23 ++- .../src/effect_report/cli/workflow.rs | 23 ++- .../src/fold_constants/cli/workflow.rs | 19 +- .../src/magic_number_report/cli/workflow.rs | 17 +- .../src/narrowing_report/cli/workflow.rs | 23 ++- .../src/type_report/cli/workflow.rs | 23 ++- .../value_propagation_report/cli/workflow.rs | 23 ++- .../src/duplicate_report/cli/workflow.rs | 25 ++- 338 files changed, 4403 insertions(+), 2060 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8a8bf1b9..45dc5d4ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -835,6 +835,7 @@ dependencies = [ "blake3", "cap-std", "libc", + "paredit-core-safety", "paredit-core-syntax", "proptest", "serde_json", diff --git a/packages/core/cli/src/report/budget.rs b/packages/core/cli/src/report/budget.rs index 4f71a4e3e..93ba02d16 100644 --- a/packages/core/cli/src/report/budget.rs +++ b/packages/core/cli/src/report/budget.rs @@ -91,7 +91,13 @@ impl Budget { /// papered over: the counts stay, and they are what a caller needs to /// decide how to narrow the request. pub fn apply(self, report: &mut Json, trimmable: &[&str]) -> Option { - if self.unlimited() || approximate_tokens(report) <= self.0 { + // The one full serialization this function pays: every later step + // updates this byte count incrementally instead of reserializing the + // whole document again, which is what made this function cost + // O(document size) per halving step on a report with several large + // trimmable arrays. + let mut total_bytes = serde_json::to_string(report).map_or(0, |text| text.len()); + if self.unlimited() || total_bytes.div_ceil(BYTES_PER_TOKEN) <= self.0 { return None; } @@ -110,7 +116,7 @@ impl Budget { // truncated list that still has a prefix is far more useful than // an empty one, and this converges in a handful of steps. loop { - if approximate_tokens(report) <= self.0 { + if total_bytes.div_ceil(BYTES_PER_TOKEN) <= self.0 { break; } let Some(array) = report.get_mut(key).and_then(Json::as_array_mut) else { @@ -119,9 +125,22 @@ impl Budget { if array.is_empty() { break; } - array.truncate(array.len() / 2); + let new_len = array.len() / 2; + // What halving removes from the document's serialized byte + // count: the dropped elements' own JSON (serialized as a + // slice, not the whole document), minus the two bracket + // characters that framed it as its own array, plus one + // boundary comma to reattach the surviving prefix to the + // array's closing bracket — except when nothing survives, in + // which case the array becomes `[]` and there is no comma to + // add back. + let dropped_slice = + serde_json::to_string(&array[new_len..]).map_or(0, |text| text.len()); + let boundary_comma = usize::from(new_len > 0); + total_bytes -= dropped_slice.saturating_sub(2) + boundary_comma; + array.truncate(new_len); } - if approximate_tokens(report) <= self.0 { + if total_bytes.div_ceil(BYTES_PER_TOKEN) <= self.0 { break; } } @@ -139,7 +158,7 @@ impl Budget { .collect(); Some(Truncation { - approximate_tokens: approximate_tokens(report), + approximate_tokens: total_bytes.div_ceil(BYTES_PER_TOKEN), budget: self.0, trimmed, }) diff --git a/packages/core/cli/src/report/graph.rs b/packages/core/cli/src/report/graph.rs index 887dd0ad2..3f2a4673c 100644 --- a/packages/core/cli/src/report/graph.rs +++ b/packages/core/cli/src/report/graph.rs @@ -209,10 +209,7 @@ pub fn dot(graph: &Graph) -> String { } fn dot_node(ids: &BTreeMap<&str, String>, node: &Node) -> String { - let id = ids - .get(node.label.as_str()) - .cloned() - .unwrap_or_else(|| "n?".to_owned()); + let id = ids.get(node.label.as_str()).map_or("n?", String::as_str); let shape = match node.shape { NodeShape::Definition => "box", NodeShape::External => "ellipse", @@ -283,10 +280,7 @@ pub fn mermaid(graph: &Graph) -> String { } fn mermaid_node(ids: &BTreeMap<&str, String>, node: &Node) -> String { - let id = ids - .get(node.label.as_str()) - .cloned() - .unwrap_or_else(|| "n0".to_owned()); + let id = ids.get(node.label.as_str()).map_or("n0", String::as_str); let label = mermaid_text(&node.label); match node.shape { NodeShape::Definition => format!("{id}[\"{label}\"]"), diff --git a/packages/core/cli/src/report/render.rs b/packages/core/cli/src/report/render.rs index f74a01af6..812ba075d 100644 --- a/packages/core/cli/src/report/render.rs +++ b/packages/core/cli/src/report/render.rs @@ -102,10 +102,11 @@ fn print_text( ); continue; } + let path_str = terminal_safe(&report.path.display()).to_string(); for finding in &report.findings { let mut row = vec![ finding.kind().to_owned(), - terminal_safe(&report.path.display()).to_string(), + path_str.clone(), report.line_of(finding).to_string(), ]; row.extend( diff --git a/packages/core/cli/src/shared.rs b/packages/core/cli/src/shared.rs index 7b16eee97..bec510f4d 100644 --- a/packages/core/cli/src/shared.rs +++ b/packages/core/cli/src/shared.rs @@ -949,6 +949,109 @@ where analyze(file, resolved, &tree, &input) } +/// [`analyze_files`]'s scheduling — parallel above the same worker threshold, +/// serial below it, largest-file-first claim order, every failure kept, same +/// [`FileAnalysis`]/[`FileFailure`] result shape — with no assumption at all +/// about what "read" or "parse" mean for one file. The caller's `process` +/// closure owns the whole per-file step, read included. +/// +/// [`analyze_files`] reads through this crate's own ambient-authority path +/// (`read_input_dialect_and_tree`), which is right for the common case — +/// files a workspace walk already discovered — but wrong for a caller with +/// its own containment guarantee to enforce on top of an arbitrary path list, +/// e.g. a `--root`-confined, symlink-refusing, TOCTOU-guarded read, as +/// `refactor-workflow`'s checkpoint and manifest commands already have and +/// must not lose by routing through a helper that reads for them. Handing the +/// whole step to the caller means this function never has an +/// ambient-authority read to bypass in the first place — a caller that needs +/// dialect detection or Lisp parsing does that inside `process` too, using +/// [`read_input_dialect_and_tree`] or [`parse_document`] directly. +pub fn analyze_files_raw(files: &[PathBuf], process: F) -> FileAnalysis +where + T: Send, + E: std::error::Error + Send, + F: Fn(&PathBuf) -> Result + Sync, +{ + let workers = worker_count(files.len()); + let results: Vec> = if workers <= 1 { + files.iter().map(&process).collect() + } else { + analyze_in_parallel_raw(files, &process, workers) + }; + + let mut analysis = FileAnalysis { + succeeded: Vec::with_capacity(results.len()), + failed: Vec::new(), + }; + for (file, result) in files.iter().zip(results) { + match result { + Ok(value) => analysis.succeeded.push(value), + Err(error) => analysis.failed.push(FileFailure { + file: file.clone(), + message: crate::error::error_chain(&error), + }), + } + } + analysis +} + +/// [`analyze_in_parallel`] for [`analyze_files_raw`]. +fn analyze_in_parallel_raw( + files: &[PathBuf], + process: &F, + workers: usize, +) -> Vec> +where + T: Send, + E: Send, + F: Fn(&PathBuf) -> Result + Sync, +{ + use std::sync::atomic::{AtomicUsize, Ordering}; + + let claim_order = claim_order_by_descending_size(files); + let cursor = AtomicUsize::new(0); + let claim_order = &claim_order; + let cursor = &cursor; + + let claimed: Vec)>> = std::thread::scope(|scope| { + let handles = (0..workers) + .map(|_| { + scope.spawn(move || { + let mut mine = Vec::new(); + loop { + let position = cursor.fetch_add(1, Ordering::Relaxed); + let Some(&index) = claim_order.get(position) else { + break; + }; + mine.push((index, process(&files[index]))); + } + mine + }) + }) + .collect::>(); + + let mut claimed = Vec::with_capacity(workers); + for handle in handles { + match handle.join() { + Ok(mine) => claimed.push(mine), + Err(payload) => std::panic::resume_unwind(payload), + } + } + claimed + }); + + let mut slots: Vec>> = files.iter().map(|_| None).collect(); + for mine in claimed { + for (index, result) in mine { + slots[index] = Some(result); + } + } + slots + .into_iter() + .map(|slot| slot.expect("every index is claimed exactly once")) + .collect() +} + /// How many workers to use for `count` files. /// /// A thread costs more than parsing a handful of small files, so a short list diff --git a/packages/core/lint-engine/src/suppression.rs b/packages/core/lint-engine/src/suppression.rs index c12c00e5a..c35f2763c 100644 --- a/packages/core/lint-engine/src/suppression.rs +++ b/packages/core/lint-engine/src/suppression.rs @@ -309,9 +309,10 @@ impl LintSuppressions { let line_span = (line_start, line_start + raw.len()); line_start += raw.len(); - let (comment_start, had_code, next_in_string) = scan_line(line, in_string); - in_string = next_in_string; - let Some(start) = comment_start else { + let scan = scan_line(line, in_string); + in_string = scan.in_string; + let had_code = scan.had_code; + let Some(start) = scan.comment_start else { continue; }; let comment = &line[start..]; @@ -709,10 +710,19 @@ fn parse_directive(comment: &str) -> Option { }) } +/// The byte offset where a line's comment begins (if any), whether +/// non-whitespace code preceded that comment, and the in-string state after +/// the line. +struct LineScan { + comment_start: Option, + had_code: bool, + in_string: bool, +} + /// Scans one line (given the incoming in-string state) and returns the byte /// offset where its comment begins (if any), whether non-whitespace code /// preceded that comment, and the in-string state after the line. -fn scan_line(line: &str, mut in_string: bool) -> (Option, bool, bool) { +fn scan_line(line: &str, mut in_string: bool) -> LineScan { let mut had_code = false; let mut chars = line.char_indices().peekable(); while let Some((offset, ch)) = chars.next() { @@ -740,7 +750,13 @@ fn scan_line(line: &str, mut in_string: bool) -> (Option, bool, bool) { chars.next(); chars.next(); } - ';' => return (Some(offset), had_code, in_string), + ';' => { + return LineScan { + comment_start: Some(offset), + had_code, + in_string, + }; + } _ => { if !ch.is_whitespace() { had_code = true; @@ -748,7 +764,11 @@ fn scan_line(line: &str, mut in_string: bool) -> (Option, bool, bool) { } } } - (None, had_code, in_string) + LineScan { + comment_start: None, + had_code, + in_string, + } } #[cfg(test)] diff --git a/packages/core/syntax/src/sexpr/edit.rs b/packages/core/syntax/src/sexpr/edit.rs index f63e7e448..8688f0141 100644 --- a/packages/core/syntax/src/sexpr/edit.rs +++ b/packages/core/syntax/src/sexpr/edit.rs @@ -601,7 +601,7 @@ fn trailing_trivia_is_opaque(tree: &SyntaxTree, start: usize, end: usize) -> boo && node.span.start().get() < end && start < node.span.end().get() }) || tree.comments.iter().any(|comment| { - !comment.text.starts_with(';') + !comment.span.slice(tree.source()).starts_with(';') && comment.span.start().get() < end && start < comment.span.end().get() }) diff --git a/packages/core/syntax/src/sexpr/formatter/core.rs b/packages/core/syntax/src/sexpr/formatter/core.rs index e413f3664..108a96d54 100644 --- a/packages/core/syntax/src/sexpr/formatter/core.rs +++ b/packages/core/syntax/src/sexpr/formatter/core.rs @@ -607,7 +607,9 @@ impl Formatter { } => { let leading = leading .iter() - .map(|&comment| self.render_comment_text(&comments[comment].text, 0)) + .map(|&comment| { + self.render_comment_text(comments[comment].span.slice(&tree.source), 0) + }) .collect(); let mut body = String::new(); @@ -620,8 +622,9 @@ impl Formatter { } let body_last_line_width = Self::last_line_width(&body); - let trailing = - trailing.map(|comment| self.render_comment_text(&comments[comment].text, 0)); + let trailing = trailing.map(|comment| { + self.render_comment_text(comments[comment].span.slice(&tree.source), 0) + }); RenderedItem::Form { leading, @@ -633,7 +636,9 @@ impl Formatter { TopLevelItem::Comments(indices) => RenderedItem::Comments( indices .iter() - .map(|&comment| self.render_comment_text(&comments[comment].text, 0)) + .map(|&comment| { + self.render_comment_text(comments[comment].span.slice(&tree.source), 0) + }) .collect(), ), } diff --git a/packages/core/syntax/src/sexpr/navigation.rs b/packages/core/syntax/src/sexpr/navigation.rs index 4218f6711..f221eaf78 100644 --- a/packages/core/syntax/src/sexpr/navigation.rs +++ b/packages/core/syntax/src/sexpr/navigation.rs @@ -240,6 +240,14 @@ impl SyntaxTree { } /// The smallest non-root node whose span contains `offset`, if any. + /// + /// Descends from the root rather than scanning the whole arena: a list's + /// span always includes its delimiters, so it strictly contains every + /// child's span, and children are non-overlapping consecutive sibling + /// subforms in source order (see how `children` is populated in + /// `parser.rs`). An offset can therefore be inside at most one child at + /// each level, so following that child down is already "the smallest + /// span containing `offset`" without needing to compare span lengths. pub(in crate::sexpr) fn innermost_node_at(&self, offset: usize) -> Option { self.innermost_node_at_offset(ByteOffset::new(offset)) } diff --git a/packages/core/syntax/src/sexpr/parser.rs b/packages/core/syntax/src/sexpr/parser.rs index 6aac64974..105f3b291 100644 --- a/packages/core/syntax/src/sexpr/parser.rs +++ b/packages/core/syntax/src/sexpr/parser.rs @@ -277,11 +277,9 @@ impl<'a> Parser<'a> { if self.suppress_depth > 0 || end.get() <= start.get() { return; } - let text = self.input[start.get()..end.get()].to_string(); let own_line = self.is_line_start(start.get()); self.comments.push(Comment { span: ByteSpan::new(start, end), - text, own_line, }); } diff --git a/packages/core/syntax/src/sexpr/tree.rs b/packages/core/syntax/src/sexpr/tree.rs index 214d53b73..63985e314 100644 --- a/packages/core/syntax/src/sexpr/tree.rs +++ b/packages/core/syntax/src/sexpr/tree.rs @@ -38,11 +38,13 @@ pub struct SyntaxTree { /// metadata the formatter needs to re-emit it without losing information. #[derive(Debug, Clone, PartialEq, Eq)] pub(in crate::sexpr) struct Comment { - /// Byte range of the comment in the original source. + /// Byte range of the comment in the original source (`; ...`, `#| ... |#`, + /// `#;
`, or `#_`), trailing whitespace preserved as parsed. + /// + /// The comment's own text is not stored here: `SyntaxTree` already owns + /// `source` for the tree's whole lifetime, so `text` is sliced from it on + /// demand instead of being duplicated into a `String` at parse time. pub(in crate::sexpr) span: ByteSpan, - /// Exact comment text (`; ...`, `#| ... |#`, `#; `, or `#_`), - /// trailing whitespace preserved as parsed. - pub(in crate::sexpr) text: String, /// `true` when only whitespace precedes the comment on its source line, i.e. /// it stands on its own line rather than trailing code. pub(in crate::sexpr) own_line: bool, @@ -735,9 +737,10 @@ impl SyntaxTree { /// parser's own record is the only way to ask "is this text a comment?" /// without re-lexing the file and getting string literals wrong. pub fn comments(&self) -> impl Iterator> { - self.comments.iter().map(|comment| SourceComment { + let source = self.source(); + self.comments.iter().map(move |comment| SourceComment { span: comment.span, - text: comment.text.as_str(), + text: comment.span.slice(source), own_line: comment.own_line, }) } diff --git a/packages/core/workspace/Cargo.toml b/packages/core/workspace/Cargo.toml index 49ed52c04..5342dea4c 100644 --- a/packages/core/workspace/Cargo.toml +++ b/packages/core/workspace/Cargo.toml @@ -11,6 +11,7 @@ repository.workspace = true [dependencies] paredit-core-syntax = { path = "../syntax" } +paredit-core-safety = { path = "../safety" } thiserror.workspace = true blake3.workspace = true serde_json.workspace = true diff --git a/packages/core/workspace/src/workspace/cache.rs b/packages/core/workspace/src/workspace/cache.rs index 0fd4db000..7d304a2b5 100644 --- a/packages/core/workspace/src/workspace/cache.rs +++ b/packages/core/workspace/src/workspace/cache.rs @@ -34,6 +34,7 @@ use std::collections::BTreeMap; use std::fs; use std::path::{Path, PathBuf}; +use std::thread; use serde_json::{Value, json}; @@ -382,49 +383,93 @@ fn read_entry(entry: &Value) -> Option { }) } +/// Below this many entries, a thread costs more than the stats it would save. +const PARALLEL_VALIDATION_THRESHOLD: usize = 8; + fn directories_are_unchanged(entry: &Value) -> bool { let Some(directories) = entry["directories"].as_array() else { return false; }; - directories.iter().all(|directory| { - let Some(path) = directory["path"].as_str() else { - return false; - }; - let path = Path::new(path); - let Ok(metadata) = fs::metadata(path) else { - return false; - }; - if !metadata.is_dir() { - return false; - } - let recorded = directory["modified_nanos"].as_str(); - let current = metadata - .modified() - .ok() - .and_then(|modified| modified.duration_since(std::time::UNIX_EPOCH).ok()) - .map(|elapsed| elapsed.as_nanos().to_string()); - if recorded.map(str::to_owned) != current { - return false; - } - // The entry count is not redundant with the mtime. Many filesystems - // record it at one-second granularity, so a file created and another - // deleted within the same second leaves the timestamp untouched. - let Some(recorded_count) = directory["entry_count"].as_u64() else { - return false; - }; - fs::read_dir(path).is_ok_and(|entries| entries.count() as u64 == recorded_count) - }) + all_parallel(directories, directory_is_unchanged) +} + +fn directory_is_unchanged(directory: &Value) -> bool { + let Some(path) = directory["path"].as_str() else { + return false; + }; + let path = Path::new(path); + let Ok(metadata) = fs::metadata(path) else { + return false; + }; + if !metadata.is_dir() { + return false; + } + let recorded = directory["modified_nanos"].as_str(); + let current = metadata + .modified() + .ok() + .and_then(|modified| modified.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|elapsed| elapsed.as_nanos().to_string()); + if recorded.map(str::to_owned) != current { + return false; + } + // The entry count is not redundant with the mtime. Many filesystems + // record it at one-second granularity, so a file created and another + // deleted within the same second leaves the timestamp untouched. + let Some(recorded_count) = directory["entry_count"].as_u64() else { + return false; + }; + fs::read_dir(path).is_ok_and(|entries| entries.count() as u64 == recorded_count) } fn ignore_files_are_unchanged(entry: &Value) -> bool { let Some(ignore_files) = entry["ignore_files"].as_array() else { return false; }; - ignore_files.iter().all(|ignore| { - let Some(path) = ignore["path"].as_str() else { - return false; - }; - ignore["stamp"].as_str() == file_stamp(Path::new(path)).as_deref() + all_parallel(ignore_files, ignore_file_is_unchanged) +} + +fn ignore_file_is_unchanged(ignore: &Value) -> bool { + let Some(path) = ignore["path"].as_str() else { + return false; + }; + ignore["stamp"].as_str() == file_stamp(Path::new(path)).as_deref() +} + +/// Whether `predicate` holds for every element of `items`. +/// +/// Below [`PARALLEL_VALIDATION_THRESHOLD`], this is `Iterator::all` with its +/// short-circuit-on-first-false intact. Above it, `items` is split into one +/// contiguous chunk per worker and each chunk is validated on its own thread; +/// `predicate` reads only its own argument (one `fs::metadata`, and for a +/// directory one `fs::read_dir(...).count()`), so no chunk touches another's +/// state. A parallel run may do marginally more stat work than a serial +/// short-circuit would when an early entry is already stale, since every +/// chunk still runs to completion — an accepted tradeoff for validating a +/// workspace with tens of thousands of entries on every cache-freshness +/// check. +fn all_parallel(items: &[T], predicate: impl Fn(&T) -> bool + Sync) -> bool { + if items.len() < PARALLEL_VALIDATION_THRESHOLD { + return items.iter().all(&predicate); + } + let workers = paredit_core_safety::limits::effective_jobs_or_available() + .get() + .min(items.len()) + .max(1); + if workers <= 1 { + return items.iter().all(&predicate); + } + let chunk_size = items.len().div_ceil(workers); + let predicate = &predicate; + thread::scope(|scope| { + let handles = items + .chunks(chunk_size) + .map(|chunk| scope.spawn(move || chunk.iter().all(predicate))) + .collect::>(); + handles.into_iter().all(|handle| match handle.join() { + Ok(result) => result, + Err(payload) => std::panic::resume_unwind(payload), + }) }) } diff --git a/packages/core/workspace/src/workspace/discovery.rs b/packages/core/workspace/src/workspace/discovery.rs index 7cc3ad9c2..08eab937c 100644 --- a/packages/core/workspace/src/workspace/discovery.rs +++ b/packages/core/workspace/src/workspace/discovery.rs @@ -656,6 +656,9 @@ fn rejected_by_globs( absolute: &Path, is_directory: bool, ) -> bool { + if options.exclude_globs.is_empty() && options.include_globs.is_empty() { + return false; + } let Some(relative) = relative_to_root(&context.root_absolute, absolute) else { return false; }; diff --git a/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs b/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs index 3cfea4c7d..3cfc6d94a 100644 --- a/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs +++ b/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs @@ -8,23 +8,21 @@ use crate::shadowed_binding_report::usecase::{ ShadowedBindingPolicyOptions, build_shadowed_binding_report, evaluate_shadowed_binding_policy, }; use paredit_core_cli::args::DialectArg; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_workspace_files}; pub fn shadowed_binding_report(args: ShadowedBindingReportArgs) -> CommandResult { let files = expand_shadowed_binding_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - - for file in &files { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_shadowed_binding_report( - file.clone(), - dialect, - &input.text, - &tree, - )?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { + build_shadowed_binding_report(file.clone(), dialect, &input.text, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_shadowed_binding_policy( ShadowedBindingPolicyOptions::new(args.fail_on_shadowed), diff --git a/packages/feature/code-metrics/src/cohesion_report/cli/workflow.rs b/packages/feature/code-metrics/src/cohesion_report/cli/workflow.rs index 3862eac03..11b204a4c 100644 --- a/packages/feature/code-metrics/src/cohesion_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/cohesion_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::cohesion_report::cli::args::CohesionReportArgs; use crate::cohesion_report::cli::render::print_isolated_report; @@ -9,11 +11,14 @@ use crate::cohesion_report::usecase::{build_cohesion_report, evaluate_fail_on_is pub fn cohesion_report(args: CohesionReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_cohesion_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_cohesion_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_isolated_policy(args.fail_on_isolated, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/debt_score_report/cli/workflow.rs b/packages/feature/code-metrics/src/debt_score_report/cli/workflow.rs index b8705a48e..937512266 100644 --- a/packages/feature/code-metrics/src/debt_score_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/debt_score_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::debt_score_report::cli::args::DebtScoreReportArgs; use crate::debt_score_report::cli::render::print_debt_report; @@ -9,11 +11,14 @@ use crate::debt_score_report::usecase::{build_debt_score_report, evaluate_fail_o pub fn debt_score_report(args: DebtScoreReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_debt_score_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_debt_score_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_debt_policy(args.fail_on_debt, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/docstring_report/cli/workflow.rs b/packages/feature/code-metrics/src/docstring_report/cli/workflow.rs index 4ffe34939..a8445402f 100644 --- a/packages/feature/code-metrics/src/docstring_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/docstring_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::docstring_report::cli::args::DocstringReportArgs; use crate::docstring_report::cli::render::print_defect_report; @@ -9,11 +11,14 @@ use crate::docstring_report::usecase::{build_docstring_report, evaluate_fail_on_ pub fn docstring_report(args: DocstringReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_docstring_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_docstring_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_defect_policy(args.fail_on_defect, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/duplication_ratio_report/cli/workflow.rs b/packages/feature/code-metrics/src/duplication_ratio_report/cli/workflow.rs index d6ca025c1..229a6b3bb 100644 --- a/packages/feature/code-metrics/src/duplication_ratio_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/duplication_ratio_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::duplication_ratio_report::cli::args::DuplicationRatioReportArgs; use crate::duplication_ratio_report::cli::render::print_duplication_report; @@ -11,11 +13,14 @@ use crate::duplication_ratio_report::usecase::{ pub fn duplication_ratio_report(args: DuplicationRatioReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplication_ratio_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_duplication_ratio_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplication_policy(args.fail_on_duplication, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/hotspot_report/cli/workflow.rs b/packages/feature/code-metrics/src/hotspot_report/cli/workflow.rs index 174a0bcdf..7219dd0a2 100644 --- a/packages/feature/code-metrics/src/hotspot_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/hotspot_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::hotspot_report::cli::args::HotspotReportArgs; use crate::hotspot_report::cli::render::print_hotspot_report; @@ -11,15 +13,18 @@ use crate::hotspot_report::usecase::{ pub fn hotspot_report(args: HotspotReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { // One `git log` per file. Batching would be faster and would also mean // a multi-repository run could not be answered per repository, which is // the case this is most useful in. let churn = measure_churn(&churn_target(file), &args.since); - reports.push(build_hotspot_report(file, dialect, &tree, &churn)); + CliResult::Ok(build_hotspot_report(file, dialect, tree, &churn)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_hotspot_policy(args.max_score, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/indentation_report/cli/workflow.rs b/packages/feature/code-metrics/src/indentation_report/cli/workflow.rs index b8123cafa..c7a50612c 100644 --- a/packages/feature/code-metrics/src/indentation_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/indentation_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::indentation_report::cli::args::IndentationReportArgs; use crate::indentation_report::cli::render::print_deviation_report; @@ -11,11 +13,14 @@ use crate::indentation_report::usecase::{ pub fn indentation_report(args: IndentationReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_indentation_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_indentation_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_deviation_policy(args.fail_on_deviation, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/line_metrics_report/cli/workflow.rs b/packages/feature/code-metrics/src/line_metrics_report/cli/workflow.rs index 1ac38560c..cef8aebb7 100644 --- a/packages/feature/code-metrics/src/line_metrics_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/line_metrics_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::line_metrics_report::cli::args::LineMetricsReportArgs; use crate::line_metrics_report::cli::render::print_line_metrics_report; @@ -12,11 +14,14 @@ pub fn line_metrics_report(args: LineMetricsReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; let thresholds = args.thresholds(); - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_line_metrics_report(file, dialect, &tree, thresholds)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_line_metrics_report(file, dialect, tree, thresholds)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_line_metrics_policy(args.fail_on_overflow, &reports); let passed = policy.passed; diff --git a/packages/feature/code-metrics/src/todo_report/cli/workflow.rs b/packages/feature/code-metrics/src/todo_report/cli/workflow.rs index fad4102f0..bd4530880 100644 --- a/packages/feature/code-metrics/src/todo_report/cli/workflow.rs +++ b/packages/feature/code-metrics/src/todo_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::todo_report::cli::args::TodoReportArgs; use crate::todo_report::cli::render::print_marker_report; @@ -9,11 +11,14 @@ use crate::todo_report::usecase::{build_todo_report, evaluate_fail_on_marker_pol pub fn todo_report(args: TodoReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_todo_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_todo_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_marker_policy(args.fail_on_marker, &reports); let passed = policy.passed; diff --git a/packages/feature/data-report/src/data_check_report/cli/workflow.rs b/packages/feature/data-report/src/data_check_report/cli/workflow.rs index f9048664d..dd9c498ee 100644 --- a/packages/feature/data-report/src/data_check_report/cli/workflow.rs +++ b/packages/feature/data-report/src/data_check_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::data_check_report::cli::args::DataCheckReportArgs; use crate::data_check_report::cli::render::print_data_check_report; @@ -11,16 +13,19 @@ use crate::data_check_report::usecase::{ pub fn data_check_report(args: DataCheckReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { // An explicit `--format` always wins; otherwise the file's path and // content decide which detectors run on top of the baseline checks. let format = args .format - .map_or_else(|| detect_data_format(file, dialect, &tree), Into::into); - reports.push(build_data_check_report(file, dialect, &tree, format)); + .map_or_else(|| detect_data_format(file, dialect, tree), Into::into); + CliResult::Ok(build_data_check_report(file, dialect, tree, format)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_finding_policy(args.fail_on_finding, &reports); let passed = policy.passed; diff --git a/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs b/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs index a538b81b3..4883725f6 100644 --- a/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs +++ b/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs @@ -1,13 +1,18 @@ use std::fs; +use std::path::PathBuf; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; -use paredit_core_cli::{CliError, CommandResult}; +use paredit_core_cli::{CliError, CliResult, CommandResult}; use paredit_core_cli::report::render::print_report; use paredit_core_cli::report::{FileFindings, ReportPolicy}; use paredit_core_cli::shared::{ - expand_input_files, read_input_dialect_and_tree, write_artifact_with_rollback, + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, + write_artifact_with_rollback, }; +use paredit_core_safety::external::ExternalError; +use paredit_core_safety::external::sbcl::Diagnostic; use paredit_core_syntax::dialect::Dialect; use super::args::ExternalDiagnosticsReportArgs; @@ -17,6 +22,45 @@ use crate::external_diagnostics_report::domain::{ }; use crate::external_diagnostics_report::usecase::{Baseline, compile_and_read, scratch_directory}; +/// One file's compile step, resolved down to what the caller does next. +/// +/// `analyze_files` treats a per-file `Err` as safe to exclude-with-a-warning, +/// which is right for a file that fails to read or parse as Lisp but wrong +/// for these three: the compiler itself failing to run, producing a +/// transcript this tool cannot read as diagnostics, or timing out. Reporting +/// any of those as "no findings" would be the worst possible answer — a +/// caller gating a refactor on this command would read a failed check as a +/// passed one — so they are carried as data here and turned into the same +/// hard, whole-command error the original serial loop returned via `?`. +enum CompileOutcome { + SkippedDialect(FileFindings), + Compiled { + report: FileFindings, + diagnostics: Vec, + }, + RunFailed { + path: PathBuf, + source: ExternalError, + }, + Unreadable { + path: PathBuf, + exit: String, + transcript: String, + }, + TimedOut { + path: PathBuf, + }, + /// The scratch directory itself could not be created. + /// + /// Not one of the three outcomes `compile_and_read` can report, but the + /// same severity: the original serial loop aborted the whole command over + /// this too (a bare `?`, before `compile_and_read` was even called), so it + /// stays a hard failure rather than becoming a silently-excluded file. + ScratchDirFailed { + source: CliError, + }, +} + pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; let implementation = Implementation::from(args.implementation); @@ -47,68 +91,61 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma None => None, }; - let mut reports = Vec::with_capacity(files.len()); - let mut every_diagnostic = Vec::new(); - - for (index, file) in files.iter().enumerate() { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + // Not `index` from an iterator position: `analyze_files` hands files to + // workers in size order, not input order, so a per-file position would + // collide across threads. Only uniqueness is needed — the scratch + // directory is created, used, and removed within one call. + let next_scratch_index = AtomicUsize::new(0); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { // The implementation is a Common Lisp one; a Clojure or Fennel file is // reported as unmodelled rather than compiled, which is the same // contract every Common-Lisp-only report in this tool follows. if dialect != Dialect::CommonLisp { - reports.push(FileFindings::new( + return CliResult::Ok(CompileOutcome::SkippedDialect(FileFindings::new( file.clone(), dialect, false, tree.source(), Vec::new(), Vec::new(), - )); - continue; + ))); } - let scratch = scratch_directory(index); - fs::create_dir_all(&scratch).map_err(CliError::io(format!( + let scratch = scratch_directory(next_scratch_index.fetch_add(1, Ordering::Relaxed)); + if let Err(source) = fs::create_dir_all(&scratch).map_err(CliError::io(format!( "failed to create scratch directory {}", scratch.display() - )))?; + ))) { + return CliResult::Ok(CompileOutcome::ScratchDirFailed { source }); + } let outcome = compile_and_read(implementation, &program, file, &scratch, budget); // The scratch directory is removed whether or not the compilation // worked: a fasl left in /tmp after a failed run is litter, and the // caller cannot be expected to know the name. let _ = fs::remove_dir_all(&scratch); - let outcome = outcome.map_err(|source| ExternalCheckError::RunFailed { - implementation: implementation.label(), - path: file.display().to_string(), - source, - })?; + let outcome = match outcome { + Ok(outcome) => outcome, + Err(source) => { + return CliResult::Ok(CompileOutcome::RunFailed { + path: file.clone(), + source, + }); + } + }; - // The implementation ran and said something this tool could not read - // as diagnostics: a missing binary (the shell's 127), a heap - // exhaustion, a `--script` that was not there. Reporting that as "no - // findings" would be the worst possible answer — a caller gating a - // refactor on this command would read a failed check as a passed one — - // so it is a hard error rather than a note. if let Some(transcript) = outcome.unparsed_transcript { - return Err(ExternalCheckError::NoReadableDiagnostics { - implementation: implementation.label(), - path: file.display().to_string(), + return CliResult::Ok(CompileOutcome::Unreadable { + path: file.clone(), exit: outcome .exit_code .map_or_else(|| "signal".to_owned(), |code| code.to_string()), transcript, - } - .into()); + }); } if outcome.timed_out { - return Err(ExternalCheckError::CompileTimedOut { - implementation: implementation.label(), - budget_ms: args.compile_timeout_ms, - path: file.display().to_string(), - } - .into()); + return CliResult::Ok(CompileOutcome::TimedOut { path: file.clone() }); } let findings = outcome @@ -116,15 +153,14 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma .iter() .map(|diagnostic| PlacedDiagnostic { diagnostic: diagnostic.clone(), - span: locate_context(&tree, diagnostic.context.as_deref()), + span: locate_context(tree, diagnostic.context.as_deref()), introduced: baseline .as_ref() .is_some_and(|baseline| !baseline.contains(diagnostic)), }) .collect::>(); - every_diagnostic.extend(outcome.diagnostics); - reports.push(FileFindings::new( + let report = FileFindings::new( file.clone(), dialect, true, @@ -134,7 +170,84 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma ("timed_out", serde_json::json!(outcome.timed_out)), ("exit_code", serde_json::json!(outcome.exit_code)), ], - )); + ); + + CliResult::Ok(CompileOutcome::Compiled { + report, + diagnostics: outcome.diagnostics, + }) + }); + + // A file that fails to read or parse as Lisp is excluded with a warning, + // same as every other report built on `analyze_files` — that failure has + // nothing to do with whether the compiler ran cleanly. It cannot make the + // whole command fail unless every file failed that way. + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + + let mut reports = Vec::with_capacity(analysis.succeeded.len()); + let mut every_diagnostic = Vec::new(); + // First bad file *in file order* wins, matching the serial loop this + // replaced: `analysis.succeeded` preserves input order, so the first of + // these three seen while walking it is the one reported, and later ones + // are dropped exactly as an early `?` would have dropped them. + let mut hard_failure: Option = None; + + for outcome in analysis.succeeded { + match outcome { + CompileOutcome::SkippedDialect(report) => reports.push(report), + CompileOutcome::Compiled { + report, + diagnostics, + } => { + every_diagnostic.extend(diagnostics); + reports.push(report); + } + CompileOutcome::RunFailed { path, source } => { + hard_failure.get_or_insert( + ExternalCheckError::RunFailed { + implementation: implementation.label(), + path: path.display().to_string(), + source, + } + .into(), + ); + } + CompileOutcome::Unreadable { + path, + exit, + transcript, + } => { + hard_failure.get_or_insert( + ExternalCheckError::NoReadableDiagnostics { + implementation: implementation.label(), + path: path.display().to_string(), + exit, + transcript, + } + .into(), + ); + } + CompileOutcome::TimedOut { path } => { + hard_failure.get_or_insert( + ExternalCheckError::CompileTimedOut { + implementation: implementation.label(), + budget_ms: args.compile_timeout_ms, + path: path.display().to_string(), + } + .into(), + ); + } + CompileOutcome::ScratchDirFailed { source } => { + hard_failure.get_or_insert(source); + } + } + } + + if let Some(failure) = hard_failure { + return Err(failure.into()); } if let Some(path) = args.save_baseline.as_deref() { diff --git a/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs b/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs index 4c0cf474b..67459d4de 100644 --- a/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs +++ b/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs @@ -9,23 +9,21 @@ use crate::unused_parameter_report::usecase::{ evaluate_unused_parameter_policy, }; use paredit_core_cli::args::DialectArg; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_workspace_files}; pub fn unused_parameter_report(args: UnusedParameterReportArgs) -> CommandResult { let files = expand_unused_parameter_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - - for file in &files { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unused_parameter_report( - file.clone(), - dialect, - &tree, - &input.text, - )?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { + build_unused_parameter_report(file.clone(), dialect, tree, &input.text) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_unused_parameter_policy( UnusedParameterReportPolicyOptions::new(args.fail_on_unused), diff --git a/packages/feature/generate/src/generate_defsystem/cli/workflow.rs b/packages/feature/generate/src/generate_defsystem/cli/workflow.rs index efae28816..9c92c3de7 100644 --- a/packages/feature/generate/src/generate_defsystem/cli/workflow.rs +++ b/packages/feature/generate/src/generate_defsystem/cli/workflow.rs @@ -1,7 +1,9 @@ +use std::path::PathBuf; + use paredit_core_cli::CliResult; use paredit_core_cli::shared::{ - expand_input_files, read_input_dialect_and_tree, write_file_with_rollback, + analyze_files, expand_input_files, total_file_failure, write_file_with_rollback, }; use paredit_core_syntax::dialect::Dialect; use paredit_core_syntax::sexpr::SyntaxTree; @@ -10,6 +12,16 @@ use crate::generate_defsystem::cli::args::GenerateDefsystemArgs; use crate::generate_defsystem::cli::render::print_defsystem_plan; use crate::generate_defsystem::usecase::plan_defsystem; +/// One file's outcome: either it parsed as Common Lisp, or it was skipped for +/// being another dialect. +/// +/// A file that fails to *read or parse* is not a third variant here — see the +/// hard-fail check below for why. +enum FileOutcome { + Parsed(PathBuf, SyntaxTree), + SkippedDialect(PathBuf), +} + pub fn generate_defsystem(args: GenerateDefsystemArgs) -> CliResult<()> { let system_name = args .name @@ -17,15 +29,30 @@ pub fn generate_defsystem(args: GenerateDefsystemArgs) -> CliResult<()> { .unwrap_or_else(|| default_system_name(&args.directory)); let files = expand_input_files(std::slice::from_ref(&args.directory), args.dialect)?; + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { + CliResult::Ok(if dialect == Dialect::CommonLisp { + FileOutcome::Parsed(file.clone(), tree.clone()) + } else { + FileOutcome::SkippedDialect(file.clone()) + }) + }); + // A generated defsystem is meant to cover every file in the directory; + // silently excluding one that failed to read or parse (the tolerant + // `analyze_files` convention used by `query`/`report` commands) would + // produce a manifest missing a file with no visible sign why. Failing + // hard here preserves this command's original behavior, where the + // per-file read/parse `?` aborted the whole run on the first bad file. + if let Some(failure) = analysis.failed.into_iter().next() { + return Err(total_file_failure(vec![failure]).into()); + } + let mut parsed = Vec::new(); let mut skipped_dialect = Vec::new(); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - if dialect != Dialect::CommonLisp { - skipped_dialect.push(file.clone()); - continue; + for outcome in analysis.succeeded { + match outcome { + FileOutcome::Parsed(file, tree) => parsed.push((file, tree)), + FileOutcome::SkippedDialect(file) => skipped_dialect.push(file), } - parsed.push((file.clone(), tree)); } let plan = plan_defsystem(&system_name, &parsed); diff --git a/packages/feature/generate/src/generate_tests/cli/workflow.rs b/packages/feature/generate/src/generate_tests/cli/workflow.rs index a9e8c93bc..bf2f56db9 100644 --- a/packages/feature/generate/src/generate_tests/cli/workflow.rs +++ b/packages/feature/generate/src/generate_tests/cli/workflow.rs @@ -1,7 +1,9 @@ +use std::path::PathBuf; + use paredit_core_cli::CliResult; use paredit_core_cli::shared::{ - expand_input_files, read_input_dialect_and_tree, write_file_with_rollback, + analyze_files, expand_input_files, total_file_failure, write_file_with_rollback, }; use paredit_core_syntax::dialect::Dialect; use paredit_core_syntax::sexpr::SyntaxTree; @@ -9,21 +11,46 @@ use paredit_feature_project_inventory::test_map_report::usecase::build_test_map_ use crate::generate_tests::cli::args::GenerateTestsArgs; use crate::generate_tests::cli::render::print_test_stub_plan; -use crate::generate_tests::usecase::build_test_stubs; +use crate::generate_tests::usecase::{TestStub, build_test_stubs}; + +/// One file's outcome: either it parsed as Common Lisp and yielded zero or +/// more stubs, or it was skipped for being another dialect. +/// +/// A file that fails to *read or parse* is not a third variant here — see the +/// hard-fail check below for why. +enum FileOutcome { + Stubs(Vec), + SkippedDialect(PathBuf), +} pub fn generate_tests(args: GenerateTestsArgs) -> CliResult<()> { let files = expand_input_files(&args.files, args.dialect)?; + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { + CliResult::Ok(if dialect == Dialect::CommonLisp { + let report = build_test_map_report(file, dialect, tree); + FileOutcome::Stubs(build_test_stubs(&report.findings)) + } else { + FileOutcome::SkippedDialect(file.clone()) + }) + }); + // Generated test stubs are meant to cover every file passed in; silently + // excluding one that failed to read or parse (the tolerant `analyze_files` + // convention used by `query`/`report` commands) would produce a stub set + // missing a file with no visible sign why. Failing hard here preserves + // this command's original behavior, where the per-file read/parse `?` + // aborted the whole run on the first bad file. + if let Some(failure) = analysis.failed.into_iter().next() { + return Err(total_file_failure(vec![failure]).into()); + } + let mut stubs = Vec::new(); let mut skipped_dialect = Vec::new(); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - if dialect != Dialect::CommonLisp { - skipped_dialect.push(file.clone()); - continue; + for outcome in analysis.succeeded { + match outcome { + FileOutcome::Stubs(file_stubs) => stubs.extend(file_stubs), + FileOutcome::SkippedDialect(file) => skipped_dialect.push(file), } - let report = build_test_map_report(file, dialect, &tree); - stubs.extend(build_test_stubs(&report.findings)); } let mut written = false; diff --git a/packages/feature/lint-build-system/src/asdf_perform_without_call_next_method/cli/workflow.rs b/packages/feature/lint-build-system/src/asdf_perform_without_call_next_method/cli/workflow.rs index 00596d198..bd25e2ac1 100644 --- a/packages/feature/lint-build-system/src/asdf_perform_without_call_next_method/cli/workflow.rs +++ b/packages/feature/lint-build-system/src/asdf_perform_without_call_next_method/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::asdf_perform_without_call_next_method::cli::args::AsdfPerformWithoutCallNextMethodReportArgs; use crate::asdf_perform_without_call_next_method::cli::render::print_asdf_perform_without_call_next_method_report; use crate::asdf_perform_without_call_next_method::usecase::{ build_asdf_perform_without_call_next_method_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn asdf_perform_without_call_next_method_report( args: AsdfPerformWithoutCallNextMethodReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_asdf_perform_without_call_next_method_report( + CliResult::Ok(build_asdf_perform_without_call_next_method_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-build-system/src/asdf_self_referential_depends_on/cli/workflow.rs b/packages/feature/lint-build-system/src/asdf_self_referential_depends_on/cli/workflow.rs index d4158fe58..49379a3be 100644 --- a/packages/feature/lint-build-system/src/asdf_self_referential_depends_on/cli/workflow.rs +++ b/packages/feature/lint-build-system/src/asdf_self_referential_depends_on/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::asdf_self_referential_depends_on::cli::args::AsdfSelfReferentialDependsOnReportArgs; use crate::asdf_self_referential_depends_on::cli::render::print_asdf_self_referential_depends_on_report; use crate::asdf_self_referential_depends_on::usecase::{ build_asdf_self_referential_depends_on_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn asdf_self_referential_depends_on_report( args: AsdfSelfReferentialDependsOnReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_asdf_self_referential_depends_on_report( + CliResult::Ok(build_asdf_self_referential_depends_on_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-build-system/src/asdf_system_missing_version/cli/workflow.rs b/packages/feature/lint-build-system/src/asdf_system_missing_version/cli/workflow.rs index 9cf723d45..a164c96b9 100644 --- a/packages/feature/lint-build-system/src/asdf_system_missing_version/cli/workflow.rs +++ b/packages/feature/lint-build-system/src/asdf_system_missing_version/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::asdf_system_missing_version::cli::args::AsdfSystemMissingVersionReportArgs; use crate::asdf_system_missing_version::cli::render::print_asdf_system_missing_version_report; use crate::asdf_system_missing_version::usecase::{ build_asdf_system_missing_version_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn asdf_system_missing_version_report( args: AsdfSystemMissingVersionReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_asdf_system_missing_version_report( + CliResult::Ok(build_asdf_system_missing_version_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-build-system/src/defpackage_without_in_package/cli/workflow.rs b/packages/feature/lint-build-system/src/defpackage_without_in_package/cli/workflow.rs index aecb53f6b..cfb757007 100644 --- a/packages/feature/lint-build-system/src/defpackage_without_in_package/cli/workflow.rs +++ b/packages/feature/lint-build-system/src/defpackage_without_in_package/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::defpackage_without_in_package::cli::args::DefpackageWithoutInPackageReportArgs; use crate::defpackage_without_in_package::cli::render::print_defpackage_without_in_package_report; use crate::defpackage_without_in_package::usecase::{ build_defpackage_without_in_package_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn defpackage_without_in_package_report( args: DefpackageWithoutInPackageReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_defpackage_without_in_package_report( + CliResult::Ok(build_defpackage_without_in_package_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-call-shape/src/deeply_nested_anonymous_lambda/cli/workflow.rs b/packages/feature/lint-call-shape/src/deeply_nested_anonymous_lambda/cli/workflow.rs index 932d2e018..6f08730df 100644 --- a/packages/feature/lint-call-shape/src/deeply_nested_anonymous_lambda/cli/workflow.rs +++ b/packages/feature/lint-call-shape/src/deeply_nested_anonymous_lambda/cli/workflow.rs @@ -1,5 +1,8 @@ -use paredit_core_cli::CommandResult; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; +use paredit_core_cli::{CliResult, CommandResult}; use crate::deeply_nested_anonymous_lambda::cli::args::DeeplyNestedAnonymousLambdaReportArgs; use crate::deeply_nested_anonymous_lambda::cli::render::print_deeply_nested_anonymous_lambda_report; @@ -12,13 +15,17 @@ pub fn deeply_nested_anonymous_lambda_report( ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_deeply_nested_anonymous_lambda_report( + CliResult::Ok(build_deeply_nested_anonymous_lambda_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-call-shape/src/nested_function_parameter_shadows_enclosing_parameter/cli/workflow.rs b/packages/feature/lint-call-shape/src/nested_function_parameter_shadows_enclosing_parameter/cli/workflow.rs index bfe6dd674..7900793de 100644 --- a/packages/feature/lint-call-shape/src/nested_function_parameter_shadows_enclosing_parameter/cli/workflow.rs +++ b/packages/feature/lint-call-shape/src/nested_function_parameter_shadows_enclosing_parameter/cli/workflow.rs @@ -1,5 +1,8 @@ -use paredit_core_cli::CommandResult; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_function_parameter_shadows_enclosing_parameter::cli::args::NestedParameterShadowReportArgs; use crate::nested_function_parameter_shadows_enclosing_parameter::cli::render::print_nested_parameter_shadow_report; @@ -10,11 +13,15 @@ use crate::nested_function_parameter_shadows_enclosing_parameter::usecase::{ pub fn nested_parameter_shadow_report(args: NestedParameterShadowReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_parameter_shadow_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_parameter_shadow_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-call-shape/src/overly_long_parameter_list/cli/workflow.rs b/packages/feature/lint-call-shape/src/overly_long_parameter_list/cli/workflow.rs index 69d6b7637..31af0c974 100644 --- a/packages/feature/lint-call-shape/src/overly_long_parameter_list/cli/workflow.rs +++ b/packages/feature/lint-call-shape/src/overly_long_parameter_list/cli/workflow.rs @@ -1,5 +1,8 @@ -use paredit_core_cli::CommandResult; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; +use paredit_core_cli::{CliResult, CommandResult}; use crate::overly_long_parameter_list::cli::args::OverlyLongParameterListReportArgs; use crate::overly_long_parameter_list::cli::render::print_overly_long_parameter_list_report; @@ -10,13 +13,17 @@ use crate::overly_long_parameter_list::usecase::{ pub fn overly_long_parameter_list_report(args: OverlyLongParameterListReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_overly_long_parameter_list_report( + CliResult::Ok(build_overly_long_parameter_list_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-call-shape/src/positional_argument_count_exceeds_readability/cli/workflow.rs b/packages/feature/lint-call-shape/src/positional_argument_count_exceeds_readability/cli/workflow.rs index 5facd0e8d..842b401f1 100644 --- a/packages/feature/lint-call-shape/src/positional_argument_count_exceeds_readability/cli/workflow.rs +++ b/packages/feature/lint-call-shape/src/positional_argument_count_exceeds_readability/cli/workflow.rs @@ -1,5 +1,8 @@ -use paredit_core_cli::CommandResult; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; +use paredit_core_cli::{CliResult, CommandResult}; use crate::positional_argument_count_exceeds_readability::cli::args::PositionalArgumentCountReportArgs; use crate::positional_argument_count_exceeds_readability::cli::render::print_positional_argument_count_report; @@ -10,13 +13,17 @@ use crate::positional_argument_count_exceeds_readability::usecase::{ pub fn positional_argument_count_report(args: PositionalArgumentCountReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_positional_argument_count_report( + CliResult::Ok(build_positional_argument_count_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-call-shape/src/stringly_typed_dispatch/cli/workflow.rs b/packages/feature/lint-call-shape/src/stringly_typed_dispatch/cli/workflow.rs index e8f37665e..333e893d4 100644 --- a/packages/feature/lint-call-shape/src/stringly_typed_dispatch/cli/workflow.rs +++ b/packages/feature/lint-call-shape/src/stringly_typed_dispatch/cli/workflow.rs @@ -1,5 +1,8 @@ -use paredit_core_cli::CommandResult; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; +use paredit_core_cli::{CliResult, CommandResult}; use crate::stringly_typed_dispatch::cli::args::StringlyTypedDispatchReportArgs; use crate::stringly_typed_dispatch::cli::render::print_stringly_typed_dispatch_report; @@ -10,11 +13,15 @@ use crate::stringly_typed_dispatch::usecase::{ pub fn stringly_typed_dispatch_report(args: StringlyTypedDispatchReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_stringly_typed_dispatch_report(file, dialect, &tree)?); + CliResult::Ok(build_stringly_typed_dispatch_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-depth/src/contains_on_non_associative/cli/workflow.rs b/packages/feature/lint-clojure-depth/src/contains_on_non_associative/cli/workflow.rs index 859f2807c..373a5b5fa 100644 --- a/packages/feature/lint-clojure-depth/src/contains_on_non_associative/cli/workflow.rs +++ b/packages/feature/lint-clojure-depth/src/contains_on_non_associative/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::contains_on_non_associative::cli::args::ContainsOnNonAssociativeReportArgs; use crate::contains_on_non_associative::cli::render::print_contains_on_non_associative_report; use crate::contains_on_non_associative::usecase::{ build_contains_on_non_associative_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn contains_on_non_associative_report( args: ContainsOnNonAssociativeReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_contains_on_non_associative_report( + CliResult::Ok(build_contains_on_non_associative_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-depth/src/go_block_blocking_channel_op/cli/workflow.rs b/packages/feature/lint-clojure-depth/src/go_block_blocking_channel_op/cli/workflow.rs index b6190ddbe..62026e4ce 100644 --- a/packages/feature/lint-clojure-depth/src/go_block_blocking_channel_op/cli/workflow.rs +++ b/packages/feature/lint-clojure-depth/src/go_block_blocking_channel_op/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::go_block_blocking_channel_op::cli::args::GoBlockBlockingChannelOpReportArgs; use crate::go_block_blocking_channel_op::cli::render::print_go_block_blocking_channel_op_report; use crate::go_block_blocking_channel_op::usecase::{ build_go_block_blocking_channel_op_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn go_block_blocking_channel_op_report( args: GoBlockBlockingChannelOpReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_go_block_blocking_channel_op_report( + CliResult::Ok(build_go_block_blocking_channel_op_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-depth/src/parking_op_outside_go_machinery/cli/workflow.rs b/packages/feature/lint-clojure-depth/src/parking_op_outside_go_machinery/cli/workflow.rs index e100b963b..a3aa50db6 100644 --- a/packages/feature/lint-clojure-depth/src/parking_op_outside_go_machinery/cli/workflow.rs +++ b/packages/feature/lint-clojure-depth/src/parking_op_outside_go_machinery/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::parking_op_outside_go_machinery::cli::args::ParkingOpOutsideGoMachineryReportArgs; use crate::parking_op_outside_go_machinery::cli::render::print_parking_op_outside_go_machinery_report; use crate::parking_op_outside_go_machinery::usecase::{ build_parking_op_outside_go_machinery_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn parking_op_outside_go_machinery_report( args: ParkingOpOutsideGoMachineryReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_parking_op_outside_go_machinery_report( + CliResult::Ok(build_parking_op_outside_go_machinery_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-depth/src/reference_type_operator_mismatch/cli/workflow.rs b/packages/feature/lint-clojure-depth/src/reference_type_operator_mismatch/cli/workflow.rs index fda9d39f5..bfe6c7f78 100644 --- a/packages/feature/lint-clojure-depth/src/reference_type_operator_mismatch/cli/workflow.rs +++ b/packages/feature/lint-clojure-depth/src/reference_type_operator_mismatch/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::reference_type_operator_mismatch::cli::args::ReferenceTypeOperatorMismatchReportArgs; use crate::reference_type_operator_mismatch::cli::render::print_reference_type_operator_mismatch_report; use crate::reference_type_operator_mismatch::usecase::{ build_reference_type_operator_mismatch_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn reference_type_operator_mismatch_report( args: ReferenceTypeOperatorMismatchReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_reference_type_operator_mismatch_report( + CliResult::Ok(build_reference_type_operator_mismatch_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-idiom/src/apply_with_literal_collection/cli/workflow.rs b/packages/feature/lint-clojure-idiom/src/apply_with_literal_collection/cli/workflow.rs index 139e559a9..47ca57537 100644 --- a/packages/feature/lint-clojure-idiom/src/apply_with_literal_collection/cli/workflow.rs +++ b/packages/feature/lint-clojure-idiom/src/apply_with_literal_collection/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::apply_with_literal_collection::cli::args::ApplyWithLiteralCollectionReportArgs; use crate::apply_with_literal_collection::cli::render::print_apply_with_literal_collection_report; use crate::apply_with_literal_collection::usecase::{ build_apply_with_literal_collection_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn apply_with_literal_collection_report( args: ApplyWithLiteralCollectionReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_apply_with_literal_collection_report( + CliResult::Ok(build_apply_with_literal_collection_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-idiom/src/def_inside_function_body/cli/workflow.rs b/packages/feature/lint-clojure-idiom/src/def_inside_function_body/cli/workflow.rs index 3a674808d..d8d7583c0 100644 --- a/packages/feature/lint-clojure-idiom/src/def_inside_function_body/cli/workflow.rs +++ b/packages/feature/lint-clojure-idiom/src/def_inside_function_body/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::def_inside_function_body::cli::args::DefInsideFunctionBodyReportArgs; use crate::def_inside_function_body::cli::render::print_def_inside_function_body_report; use crate::def_inside_function_body::usecase::{ build_def_inside_function_body_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn def_inside_function_body_report(args: DefInsideFunctionBodyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_def_inside_function_body_report(file, dialect, &tree)?); + CliResult::Ok(build_def_inside_function_body_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-idiom/src/single_key_nested_path/cli/workflow.rs b/packages/feature/lint-clojure-idiom/src/single_key_nested_path/cli/workflow.rs index e5330a0be..aa3cc2b30 100644 --- a/packages/feature/lint-clojure-idiom/src/single_key_nested_path/cli/workflow.rs +++ b/packages/feature/lint-clojure-idiom/src/single_key_nested_path/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_key_nested_path::cli::args::SingleKeyNestedPathReportArgs; use crate::single_key_nested_path::cli::render::print_single_key_nested_path_report; use crate::single_key_nested_path::usecase::{ build_single_key_nested_path_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_key_nested_path_report(args: SingleKeyNestedPathReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_key_nested_path_report(file, dialect, &tree)?); + CliResult::Ok(build_single_key_nested_path_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-clojure-idiom/src/with_open_returns_lazy_seq/cli/workflow.rs b/packages/feature/lint-clojure-idiom/src/with_open_returns_lazy_seq/cli/workflow.rs index 9f0ae269a..8c35ec2d8 100644 --- a/packages/feature/lint-clojure-idiom/src/with_open_returns_lazy_seq/cli/workflow.rs +++ b/packages/feature/lint-clojure-idiom/src/with_open_returns_lazy_seq/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::with_open_returns_lazy_seq::cli::args::WithOpenLazySeqReportArgs; use crate::with_open_returns_lazy_seq::cli::render::print_with_open_returns_lazy_seq_report; use crate::with_open_returns_lazy_seq::usecase::{ build_with_open_returns_lazy_seq_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn with_open_returns_lazy_seq_report(args: WithOpenLazySeqReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_with_open_returns_lazy_seq_report( + CliResult::Ok(build_with_open_returns_lazy_seq_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-compile-time/src/defconstant_non_eql_value/cli/workflow.rs b/packages/feature/lint-compile-time/src/defconstant_non_eql_value/cli/workflow.rs index 35bb763db..7bd06372c 100644 --- a/packages/feature/lint-compile-time/src/defconstant_non_eql_value/cli/workflow.rs +++ b/packages/feature/lint-compile-time/src/defconstant_non_eql_value/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::defconstant_non_eql_value::cli::args::DefconstantNonEqlValueReportArgs; use crate::defconstant_non_eql_value::cli::render::print_defconstant_non_eql_value_report; use crate::defconstant_non_eql_value::usecase::{ build_defconstant_non_eql_value_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn defconstant_non_eql_value_report(args: DefconstantNonEqlValueReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_defconstant_non_eql_value_report( + CliResult::Ok(build_defconstant_non_eql_value_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-compile-time/src/eval_when_body_never_runs/cli/workflow.rs b/packages/feature/lint-compile-time/src/eval_when_body_never_runs/cli/workflow.rs index b48acf621..d31559205 100644 --- a/packages/feature/lint-compile-time/src/eval_when_body_never_runs/cli/workflow.rs +++ b/packages/feature/lint-compile-time/src/eval_when_body_never_runs/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eval_when_body_never_runs::cli::args::EvalWhenBodyNeverRunsReportArgs; use crate::eval_when_body_never_runs::cli::render::print_eval_when_body_never_runs_report; use crate::eval_when_body_never_runs::usecase::{ build_eval_when_body_never_runs_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eval_when_body_never_runs_report(args: EvalWhenBodyNeverRunsReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eval_when_body_never_runs_report( + CliResult::Ok(build_eval_when_body_never_runs_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-compile-time/src/eval_when_execute_only/cli/workflow.rs b/packages/feature/lint-compile-time/src/eval_when_execute_only/cli/workflow.rs index 3c3292126..c4c82f683 100644 --- a/packages/feature/lint-compile-time/src/eval_when_execute_only/cli/workflow.rs +++ b/packages/feature/lint-compile-time/src/eval_when_execute_only/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eval_when_execute_only::cli::args::EvalWhenExecuteOnlyReportArgs; use crate::eval_when_execute_only::cli::render::print_eval_when_execute_only_report; use crate::eval_when_execute_only::usecase::{ build_eval_when_execute_only_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eval_when_execute_only_report(args: EvalWhenExecuteOnlyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eval_when_execute_only_report(file, dialect, &tree)?); + CliResult::Ok(build_eval_when_execute_only_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/atom_swap_with_side_effect/cli/workflow.rs b/packages/feature/lint-concurrency/src/atom_swap_with_side_effect/cli/workflow.rs index f064cd04d..65c85f315 100644 --- a/packages/feature/lint-concurrency/src/atom_swap_with_side_effect/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/atom_swap_with_side_effect/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::atom_swap_with_side_effect::cli::args::AtomSwapWithSideEffectReportArgs; use crate::atom_swap_with_side_effect::cli::render::print_atom_swap_with_side_effect_report; use crate::atom_swap_with_side_effect::usecase::{ build_atom_swap_with_side_effect_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn atom_swap_with_side_effect_report(args: AtomSwapWithSideEffectReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_atom_swap_with_side_effect_report( + CliResult::Ok(build_atom_swap_with_side_effect_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/dynamic_var_bound_across_thread_boundary/cli/workflow.rs b/packages/feature/lint-concurrency/src/dynamic_var_bound_across_thread_boundary/cli/workflow.rs index 3e9cf9281..17b8f8f89 100644 --- a/packages/feature/lint-concurrency/src/dynamic_var_bound_across_thread_boundary/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/dynamic_var_bound_across_thread_boundary/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::dynamic_var_bound_across_thread_boundary::cli::args::DynamicVarBoundAcrossThreadBoundaryReportArgs; use crate::dynamic_var_bound_across_thread_boundary::cli::render::print_dynamic_var_bound_across_thread_boundary_report; use crate::dynamic_var_bound_across_thread_boundary::usecase::{ build_dynamic_var_bound_across_thread_boundary_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn dynamic_var_bound_across_thread_boundary_report( args: DynamicVarBoundAcrossThreadBoundaryReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_dynamic_var_bound_across_thread_boundary_report( + CliResult::Ok(build_dynamic_var_bound_across_thread_boundary_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/future_promise_never_realized/cli/workflow.rs b/packages/feature/lint-concurrency/src/future_promise_never_realized/cli/workflow.rs index 89c9f0526..5add0aecc 100644 --- a/packages/feature/lint-concurrency/src/future_promise_never_realized/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/future_promise_never_realized/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::future_promise_never_realized::cli::args::FuturePromiseNeverRealizedReportArgs; use crate::future_promise_never_realized::cli::render::print_future_promise_never_realized_report; use crate::future_promise_never_realized::usecase::{ build_future_promise_never_realized_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn future_promise_never_realized_report( args: FuturePromiseNeverRealizedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_future_promise_never_realized_report( + CliResult::Ok(build_future_promise_never_realized_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/lock_acquired_not_released/cli/workflow.rs b/packages/feature/lint-concurrency/src/lock_acquired_not_released/cli/workflow.rs index 1ae7d27e5..cdeef7829 100644 --- a/packages/feature/lint-concurrency/src/lock_acquired_not_released/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/lock_acquired_not_released/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::lock_acquired_not_released::cli::args::LockAcquiredNotReleasedReportArgs; use crate::lock_acquired_not_released::cli::render::print_lock_acquired_not_released_report; use crate::lock_acquired_not_released::usecase::{ build_lock_acquired_not_released_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn lock_acquired_not_released_report(args: LockAcquiredNotReleasedReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_lock_acquired_not_released_report( + CliResult::Ok(build_lock_acquired_not_released_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/recursive_lock_reentry_risk/cli/workflow.rs b/packages/feature/lint-concurrency/src/recursive_lock_reentry_risk/cli/workflow.rs index d16845342..1badcf726 100644 --- a/packages/feature/lint-concurrency/src/recursive_lock_reentry_risk/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/recursive_lock_reentry_risk/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::recursive_lock_reentry_risk::cli::args::RecursiveLockReentryRiskReportArgs; use crate::recursive_lock_reentry_risk::cli::render::print_recursive_lock_reentry_risk_report; use crate::recursive_lock_reentry_risk::usecase::{ build_recursive_lock_reentry_risk_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn recursive_lock_reentry_risk_report( args: RecursiveLockReentryRiskReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_recursive_lock_reentry_risk_report( + CliResult::Ok(build_recursive_lock_reentry_risk_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/thread_spawned_without_error_handler/cli/workflow.rs b/packages/feature/lint-concurrency/src/thread_spawned_without_error_handler/cli/workflow.rs index 085639e8f..2d2130a0a 100644 --- a/packages/feature/lint-concurrency/src/thread_spawned_without_error_handler/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/thread_spawned_without_error_handler/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::thread_spawned_without_error_handler::cli::args::ThreadSpawnedWithoutErrorHandlerReportArgs; use crate::thread_spawned_without_error_handler::cli::render::print_thread_spawned_without_error_handler_report; use crate::thread_spawned_without_error_handler::usecase::{ build_thread_spawned_without_error_handler_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn thread_spawned_without_error_handler_report( args: ThreadSpawnedWithoutErrorHandlerReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_thread_spawned_without_error_handler_report( + CliResult::Ok(build_thread_spawned_without_error_handler_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-concurrency/src/unsynchronized_shared_mutation/cli/workflow.rs b/packages/feature/lint-concurrency/src/unsynchronized_shared_mutation/cli/workflow.rs index a78446843..60dd98b0f 100644 --- a/packages/feature/lint-concurrency/src/unsynchronized_shared_mutation/cli/workflow.rs +++ b/packages/feature/lint-concurrency/src/unsynchronized_shared_mutation/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unsynchronized_shared_mutation::cli::args::UnsynchronizedSharedMutationReportArgs; use crate::unsynchronized_shared_mutation::cli::render::print_unsynchronized_shared_mutation_report; use crate::unsynchronized_shared_mutation::usecase::{ build_unsynchronized_shared_mutation_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn unsynchronized_shared_mutation_report( args: UnsynchronizedSharedMutationReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unsynchronized_shared_mutation_report( + CliResult::Ok(build_unsynchronized_shared_mutation_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/cerror_missing_continue_format/cli/workflow.rs b/packages/feature/lint-condition-system/src/cerror_missing_continue_format/cli/workflow.rs index c05510b57..bfbf1e91b 100644 --- a/packages/feature/lint-condition-system/src/cerror_missing_continue_format/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/cerror_missing_continue_format/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::cerror_missing_continue_format::cli::args::CerrorMissingContinueFormatReportArgs; use crate::cerror_missing_continue_format::cli::render::print_cerror_missing_continue_format_report; use crate::cerror_missing_continue_format::usecase::{ build_cerror_missing_continue_format_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn cerror_missing_continue_format_report( args: CerrorMissingContinueFormatReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_cerror_missing_continue_format_report( + CliResult::Ok(build_cerror_missing_continue_format_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/define_condition_empty_superclass_list/cli/workflow.rs b/packages/feature/lint-condition-system/src/define_condition_empty_superclass_list/cli/workflow.rs index b3b4546ce..88f511bc2 100644 --- a/packages/feature/lint-condition-system/src/define_condition_empty_superclass_list/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/define_condition_empty_superclass_list/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::define_condition_empty_superclass_list::cli::args::DefineConditionEmptySuperclassListReportArgs; use crate::define_condition_empty_superclass_list::cli::render::print_define_condition_empty_superclass_list_report; use crate::define_condition_empty_superclass_list::usecase::{ build_define_condition_empty_superclass_list_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn define_condition_empty_superclass_list_report( args: DefineConditionEmptySuperclassListReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_define_condition_empty_superclass_list_report( + CliResult::Ok(build_define_condition_empty_superclass_list_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/define_condition_missing_report_for_error_type/cli/workflow.rs b/packages/feature/lint-condition-system/src/define_condition_missing_report_for_error_type/cli/workflow.rs index 7460241aa..795fbef71 100644 --- a/packages/feature/lint-condition-system/src/define_condition_missing_report_for_error_type/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/define_condition_missing_report_for_error_type/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::define_condition_missing_report_for_error_type::cli::args::DefineConditionMissingReportForErrorTypeReportArgs; use crate::define_condition_missing_report_for_error_type::cli::render::print_define_condition_missing_report_for_error_type_report; use crate::define_condition_missing_report_for_error_type::usecase::{ build_define_condition_missing_report_for_error_type_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn define_condition_missing_report_for_error_type_report( args: DefineConditionMissingReportForErrorTypeReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_define_condition_missing_report_for_error_type_report( + CliResult::Ok(build_define_condition_missing_report_for_error_type_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/handler_bind_handler_returns_bare_value/cli/workflow.rs b/packages/feature/lint-condition-system/src/handler_bind_handler_returns_bare_value/cli/workflow.rs index 97a57490c..f3e9fbd49 100644 --- a/packages/feature/lint-condition-system/src/handler_bind_handler_returns_bare_value/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/handler_bind_handler_returns_bare_value/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::handler_bind_handler_returns_bare_value::cli::args::HandlerBindHandlerReturnsBareValueReportArgs; use crate::handler_bind_handler_returns_bare_value::cli::render::print_handler_bind_handler_returns_bare_value_report; use crate::handler_bind_handler_returns_bare_value::usecase::{ build_handler_bind_handler_returns_bare_value_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn handler_bind_handler_returns_bare_value_report( args: HandlerBindHandlerReturnsBareValueReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_handler_bind_handler_returns_bare_value_report( + CliResult::Ok(build_handler_bind_handler_returns_bare_value_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/ignore_errors_wraps_non_error_signal/cli/workflow.rs b/packages/feature/lint-condition-system/src/ignore_errors_wraps_non_error_signal/cli/workflow.rs index 0a3d1317e..4221c6880 100644 --- a/packages/feature/lint-condition-system/src/ignore_errors_wraps_non_error_signal/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/ignore_errors_wraps_non_error_signal/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::ignore_errors_wraps_non_error_signal::cli::args::IgnoreErrorsWrapsNonErrorSignalReportArgs; use crate::ignore_errors_wraps_non_error_signal::cli::render::print_ignore_errors_wraps_non_error_signal_report; use crate::ignore_errors_wraps_non_error_signal::usecase::{ build_ignore_errors_wraps_non_error_signal_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn ignore_errors_wraps_non_error_signal_report( args: IgnoreErrorsWrapsNonErrorSignalReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_ignore_errors_wraps_non_error_signal_report( + CliResult::Ok(build_ignore_errors_wraps_non_error_signal_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/restart_case_clause_without_report/cli/workflow.rs b/packages/feature/lint-condition-system/src/restart_case_clause_without_report/cli/workflow.rs index 77581c8e8..0055ad8f8 100644 --- a/packages/feature/lint-condition-system/src/restart_case_clause_without_report/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/restart_case_clause_without_report/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::restart_case_clause_without_report::cli::args::RestartCaseClauseWithoutReportReportArgs; use crate::restart_case_clause_without_report::cli::render::print_restart_case_clause_without_report_report; use crate::restart_case_clause_without_report::usecase::{ build_restart_case_clause_without_report_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn restart_case_clause_without_report_report( args: RestartCaseClauseWithoutReportReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_restart_case_clause_without_report_report( + CliResult::Ok(build_restart_case_clause_without_report_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-condition-system/src/signal_on_error_condition_returns_silently/cli/workflow.rs b/packages/feature/lint-condition-system/src/signal_on_error_condition_returns_silently/cli/workflow.rs index e31551a47..d4214d9c6 100644 --- a/packages/feature/lint-condition-system/src/signal_on_error_condition_returns_silently/cli/workflow.rs +++ b/packages/feature/lint-condition-system/src/signal_on_error_condition_returns_silently/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::signal_on_error_condition_returns_silently::cli::args::SignalOnErrorConditionReturnsSilentlyReportArgs; use crate::signal_on_error_condition_returns_silently::cli::render::print_signal_on_error_condition_returns_silently_report; use crate::signal_on_error_condition_returns_silently::usecase::{ build_signal_on_error_condition_returns_silently_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn signal_on_error_condition_returns_silently_report( args: SignalOnErrorConditionReturnsSilentlyReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_signal_on_error_condition_returns_silently_report( + CliResult::Ok(build_signal_on_error_condition_returns_silently_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/case_key_eql_pitfall/cli/workflow.rs b/packages/feature/lint-conditional/src/case_key_eql_pitfall/cli/workflow.rs index 4d66f88c5..efc62f2a3 100644 --- a/packages/feature/lint-conditional/src/case_key_eql_pitfall/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/case_key_eql_pitfall/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::case_key_eql_pitfall::cli::args::CaseKeyEqlPitfallReportArgs; use crate::case_key_eql_pitfall::cli::render::print_case_key_eql_pitfall_report; use crate::case_key_eql_pitfall::usecase::{ build_case_key_eql_pitfall_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn case_key_eql_pitfall_report(args: CaseKeyEqlPitfallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_case_key_eql_pitfall_report(file, dialect, &tree)?); + CliResult::Ok(build_case_key_eql_pitfall_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/case_nil_key/cli/workflow.rs b/packages/feature/lint-conditional/src/case_nil_key/cli/workflow.rs index 97c15fff2..6ed556c83 100644 --- a/packages/feature/lint-conditional/src/case_nil_key/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/case_nil_key/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::case_nil_key::cli::args::CaseNilKeyReportArgs; use crate::case_nil_key::cli::render::print_case_nil_key_report; use crate::case_nil_key::usecase::{build_case_nil_key_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn case_nil_key_report(args: CaseNilKeyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_case_nil_key_report(file, dialect, &tree)?); + CliResult::Ok(build_case_nil_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/cond_t_clause/cli/workflow.rs b/packages/feature/lint-conditional/src/cond_t_clause/cli/workflow.rs index 456af671a..7cf3e3056 100644 --- a/packages/feature/lint-conditional/src/cond_t_clause/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/cond_t_clause/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::cond_t_clause::cli::args::CondTClauseReportArgs; use crate::cond_t_clause::cli::render::print_cond_t_clause_report; use crate::cond_t_clause::usecase::{ build_cond_t_clause_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn cond_t_clause_report(args: CondTClauseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_cond_t_clause_report(file, dialect, &tree)?); + CliResult::Ok(build_cond_t_clause_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/cond_to_case_candidate/cli/workflow.rs b/packages/feature/lint-conditional/src/cond_to_case_candidate/cli/workflow.rs index 47fce3d8f..6b2c8892f 100644 --- a/packages/feature/lint-conditional/src/cond_to_case_candidate/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/cond_to_case_candidate/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::cond_to_case_candidate::cli::args::CondToCaseCandidateReportArgs; use crate::cond_to_case_candidate::cli::render::print_cond_to_case_candidate_report; use crate::cond_to_case_candidate::usecase::{ build_cond_to_case_candidate_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn cond_to_case_candidate_report(args: CondToCaseCandidateReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_cond_to_case_candidate_report(file, dialect, &tree)?); + CliResult::Ok(build_cond_to_case_candidate_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/constant_if_test/cli/workflow.rs b/packages/feature/lint-conditional/src/constant_if_test/cli/workflow.rs index beac87cdf..9734329dd 100644 --- a/packages/feature/lint-conditional/src/constant_if_test/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/constant_if_test/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::constant_if_test::cli::args::ConstantIfTestReportArgs; use crate::constant_if_test::cli::render::print_constant_if_test_report; use crate::constant_if_test::usecase::{ build_constant_if_test_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn constant_if_test_report(args: ConstantIfTestReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_constant_if_test_report(file, dialect, &tree)?); + CliResult::Ok(build_constant_if_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/constant_when_test/cli/workflow.rs b/packages/feature/lint-conditional/src/constant_when_test/cli/workflow.rs index 3d4f46fb6..6b3774691 100644 --- a/packages/feature/lint-conditional/src/constant_when_test/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/constant_when_test/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::constant_when_test::cli::args::ConstantWhenTestReportArgs; use crate::constant_when_test::cli::render::print_constant_when_test_report; use crate::constant_when_test::usecase::{ build_constant_when_test_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn constant_when_test_report(args: ConstantWhenTestReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_constant_when_test_report(file, dialect, &tree)?); + CliResult::Ok(build_constant_when_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/de_morgan/cli/workflow.rs b/packages/feature/lint-conditional/src/de_morgan/cli/workflow.rs index 3eb47019a..aafb839bf 100644 --- a/packages/feature/lint-conditional/src/de_morgan/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/de_morgan/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::de_morgan::cli::args::DeMorganReportArgs; use crate::de_morgan::cli::render::print_de_morgan_report; use crate::de_morgan::usecase::{build_de_morgan_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn de_morgan_report(args: DeMorganReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_de_morgan_report(file, dialect, &tree)?); + CliResult::Ok(build_de_morgan_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/dead_boolean_operand/cli/workflow.rs b/packages/feature/lint-conditional/src/dead_boolean_operand/cli/workflow.rs index 1d26e8e91..cca7abd9a 100644 --- a/packages/feature/lint-conditional/src/dead_boolean_operand/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/dead_boolean_operand/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::dead_boolean_operand::cli::args::DeadBooleanOperandReportArgs; use crate::dead_boolean_operand::cli::render::print_dead_boolean_operand_report; use crate::dead_boolean_operand::usecase::{ build_dead_boolean_operand_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn dead_boolean_operand_report(args: DeadBooleanOperandReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_dead_boolean_operand_report(file, dialect, &tree)?); + CliResult::Ok(build_dead_boolean_operand_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/duplicate_boolean_operands/cli/workflow.rs b/packages/feature/lint-conditional/src/duplicate_boolean_operands/cli/workflow.rs index 37aca2833..f59a005ca 100644 --- a/packages/feature/lint-conditional/src/duplicate_boolean_operands/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/duplicate_boolean_operands/cli/workflow.rs @@ -1,20 +1,26 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_boolean_operands::cli::args::DuplicateBooleanOperandReportArgs; use crate::duplicate_boolean_operands::cli::render::print_duplicate_boolean_operand_report; use crate::duplicate_boolean_operands::usecase::{ build_duplicate_boolean_operand_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn duplicate_boolean_operand_report(args: DuplicateBooleanOperandReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_boolean_operand_report( + CliResult::Ok(build_duplicate_boolean_operand_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/duplicate_case_keys/cli/workflow.rs b/packages/feature/lint-conditional/src/duplicate_case_keys/cli/workflow.rs index 24b0b1c05..1c257abf9 100644 --- a/packages/feature/lint-conditional/src/duplicate_case_keys/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/duplicate_case_keys/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_case_keys::cli::args::DuplicateCaseKeyReportArgs; use crate::duplicate_case_keys::cli::render::print_duplicate_case_key_report; use crate::duplicate_case_keys::usecase::{ build_duplicate_case_key_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn duplicate_case_key_report(args: DuplicateCaseKeyReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_case_key_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_case_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/duplicate_cond_tests/cli/workflow.rs b/packages/feature/lint-conditional/src/duplicate_cond_tests/cli/workflow.rs index a289b6902..ca0134114 100644 --- a/packages/feature/lint-conditional/src/duplicate_cond_tests/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/duplicate_cond_tests/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_cond_tests::cli::args::DuplicateCondTestReportArgs; use crate::duplicate_cond_tests::cli::render::print_duplicate_cond_test_report; use crate::duplicate_cond_tests::usecase::{ build_duplicate_cond_test_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn duplicate_cond_test_report(args: DuplicateCondTestReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_cond_test_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_cond_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/empty_body/cli/workflow.rs b/packages/feature/lint-conditional/src/empty_body/cli/workflow.rs index 3ad99dc06..f70f7abaa 100644 --- a/packages/feature/lint-conditional/src/empty_body/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/empty_body/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::empty_body::cli::args::EmptyBodyReportArgs; use crate::empty_body::cli::render::print_empty_body_report; use crate::empty_body::usecase::{build_empty_body_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn empty_body_report(args: EmptyBodyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_empty_body_report(file, dialect, &tree)?); + CliResult::Ok(build_empty_body_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/exhaustive_case_otherwise/cli/workflow.rs b/packages/feature/lint-conditional/src/exhaustive_case_otherwise/cli/workflow.rs index 26cc82d8d..bd17548e8 100644 --- a/packages/feature/lint-conditional/src/exhaustive_case_otherwise/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/exhaustive_case_otherwise/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::exhaustive_case_otherwise::cli::args::ExhaustiveCaseOtherwiseReportArgs; use crate::exhaustive_case_otherwise::cli::render::print_exhaustive_case_otherwise_report; use crate::exhaustive_case_otherwise::usecase::{ build_exhaustive_case_otherwise_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn exhaustive_case_otherwise_report(args: ExhaustiveCaseOtherwiseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_exhaustive_case_otherwise_report( + CliResult::Ok(build_exhaustive_case_otherwise_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/identical_if_branches/cli/workflow.rs b/packages/feature/lint-conditional/src/identical_if_branches/cli/workflow.rs index a87bfed0d..39c51bf48 100644 --- a/packages/feature/lint-conditional/src/identical_if_branches/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/identical_if_branches/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::identical_if_branches::cli::args::IdenticalIfBranchReportArgs; use crate::identical_if_branches::cli::render::print_identical_if_branch_report; use crate::identical_if_branches::usecase::{ build_identical_if_branch_report, evaluate_fail_on_identical_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn identical_if_branch_report(args: IdenticalIfBranchReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_identical_if_branch_report(file, dialect, &tree)?); + CliResult::Ok(build_identical_if_branch_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_identical_policy(args.fail_on_identical, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/if_arity/cli/workflow.rs b/packages/feature/lint-conditional/src/if_arity/cli/workflow.rs index 77681ad13..08d7e616c 100644 --- a/packages/feature/lint-conditional/src/if_arity/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/if_arity/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::if_arity::cli::args::IfArityReportArgs; use crate::if_arity::cli::render::print_if_arity_report; use crate::if_arity::usecase::{build_if_arity_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn if_arity_report(args: IfArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_if_arity_report(file, dialect, &tree)?); + CliResult::Ok(build_if_arity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/if_not/cli/workflow.rs b/packages/feature/lint-conditional/src/if_not/cli/workflow.rs index 00b03eb10..1b0afd723 100644 --- a/packages/feature/lint-conditional/src/if_not/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/if_not/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::if_not::cli::args::IfNotReportArgs; use crate::if_not::cli::render::print_if_not_report; use crate::if_not::usecase::{build_if_not_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn if_not_report(args: IfNotReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_if_not_report(file, dialect, &tree)?); + CliResult::Ok(build_if_not_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/if_to_or/cli/workflow.rs b/packages/feature/lint-conditional/src/if_to_or/cli/workflow.rs index 082159157..b66d22ac0 100644 --- a/packages/feature/lint-conditional/src/if_to_or/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/if_to_or/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::if_to_or::cli::args::IfToOrReportArgs; use crate::if_to_or::cli::render::print_if_to_or_report; use crate::if_to_or::usecase::{build_if_to_or_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn if_to_or_report(args: IfToOrReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_if_to_or_report(file, dialect, &tree)?); + CliResult::Ok(build_if_to_or_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/if_to_unless/cli/workflow.rs b/packages/feature/lint-conditional/src/if_to_unless/cli/workflow.rs index 1bf488030..5fa604194 100644 --- a/packages/feature/lint-conditional/src/if_to_unless/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/if_to_unless/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::if_to_unless::cli::args::IfToUnlessReportArgs; use crate::if_to_unless::cli::render::print_if_to_unless_report; use crate::if_to_unless::usecase::{build_if_to_unless_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn if_to_unless_report(args: IfToUnlessReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_if_to_unless_report(file, dialect, &tree)?); + CliResult::Ok(build_if_to_unless_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/malformed_case_clause/cli/workflow.rs b/packages/feature/lint-conditional/src/malformed_case_clause/cli/workflow.rs index d8539cd3a..b37777fbc 100644 --- a/packages/feature/lint-conditional/src/malformed_case_clause/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/malformed_case_clause/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::malformed_case_clause::cli::args::MalformedCaseClauseReportArgs; use crate::malformed_case_clause::cli::render::print_malformed_case_clause_report; use crate::malformed_case_clause::usecase::{ build_malformed_case_clause_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn malformed_case_clause_report(args: MalformedCaseClauseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_malformed_case_clause_report(file, dialect, &tree)?); + CliResult::Ok(build_malformed_case_clause_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/malformed_cond_clause/cli/workflow.rs b/packages/feature/lint-conditional/src/malformed_cond_clause/cli/workflow.rs index 6befaa514..de05a1808 100644 --- a/packages/feature/lint-conditional/src/malformed_cond_clause/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/malformed_cond_clause/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::malformed_cond_clause::cli::args::MalformedCondClauseReportArgs; use crate::malformed_cond_clause::cli::render::print_malformed_cond_clause_report; use crate::malformed_cond_clause::usecase::{ build_malformed_cond_clause_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn malformed_cond_clause_report(args: MalformedCondClauseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_malformed_cond_clause_report(file, dialect, &tree)?); + CliResult::Ok(build_malformed_cond_clause_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/negated_comparison/cli/workflow.rs b/packages/feature/lint-conditional/src/negated_comparison/cli/workflow.rs index 132c922be..3ee26a6b8 100644 --- a/packages/feature/lint-conditional/src/negated_comparison/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/negated_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::negated_comparison::cli::args::NegatedComparisonReportArgs; use crate::negated_comparison::cli::render::print_negated_comparison_report; use crate::negated_comparison::usecase::{ build_negated_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn negated_comparison_report(args: NegatedComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_negated_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_negated_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/negated_if/cli/workflow.rs b/packages/feature/lint-conditional/src/negated_if/cli/workflow.rs index 92add2a45..4a195cd29 100644 --- a/packages/feature/lint-conditional/src/negated_if/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/negated_if/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::negated_if::cli::args::NegatedIfReportArgs; use crate::negated_if::cli::render::print_negated_if_report; use crate::negated_if::usecase::{build_negated_if_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn negated_if_report(args: NegatedIfReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_negated_if_report(file, dialect, &tree)?); + CliResult::Ok(build_negated_if_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/negated_when_unless/cli/workflow.rs b/packages/feature/lint-conditional/src/negated_when_unless/cli/workflow.rs index 77fd188f7..468a01c0e 100644 --- a/packages/feature/lint-conditional/src/negated_when_unless/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/negated_when_unless/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::negated_when_unless::cli::args::NegatedWhenUnlessReportArgs; use crate::negated_when_unless::cli::render::print_negated_when_unless_report; use crate::negated_when_unless::usecase::{ build_negated_when_unless_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn negated_when_unless_report(args: NegatedWhenUnlessReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_negated_when_unless_report(file, dialect, &tree)?); + CliResult::Ok(build_negated_when_unless_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/nested_boolean/cli/workflow.rs b/packages/feature/lint-conditional/src/nested_boolean/cli/workflow.rs index f706c6ba3..f7d17c532 100644 --- a/packages/feature/lint-conditional/src/nested_boolean/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/nested_boolean/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_boolean::cli::args::NestedBooleanReportArgs; use crate::nested_boolean::cli::render::print_nested_boolean_report; use crate::nested_boolean::usecase::{ build_nested_boolean_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_boolean_report(args: NestedBooleanReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_boolean_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_boolean_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/nested_cond_flattenable/cli/workflow.rs b/packages/feature/lint-conditional/src/nested_cond_flattenable/cli/workflow.rs index 4aa12bb75..619a82b00 100644 --- a/packages/feature/lint-conditional/src/nested_cond_flattenable/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/nested_cond_flattenable/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_cond_flattenable::cli::args::NestedCondFlattenableReportArgs; use crate::nested_cond_flattenable::cli::render::print_nested_cond_flattenable_report; use crate::nested_cond_flattenable::usecase::{ build_nested_cond_flattenable_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_cond_flattenable_report(args: NestedCondFlattenableReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_cond_flattenable_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_cond_flattenable_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/nested_unless/cli/workflow.rs b/packages/feature/lint-conditional/src/nested_unless/cli/workflow.rs index d1017e1b8..88e66b206 100644 --- a/packages/feature/lint-conditional/src/nested_unless/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/nested_unless/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_unless::cli::args::NestedUnlessReportArgs; use crate::nested_unless::cli::render::print_nested_unless_report; use crate::nested_unless::usecase::{ build_nested_unless_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_unless_report(args: NestedUnlessReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_unless_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_unless_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/nested_when/cli/workflow.rs b/packages/feature/lint-conditional/src/nested_when/cli/workflow.rs index bdaf905c2..6e2641ccf 100644 --- a/packages/feature/lint-conditional/src/nested_when/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/nested_when/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_when::cli::args::NestedWhenReportArgs; use crate::nested_when::cli::render::print_nested_when_report; use crate::nested_when::usecase::{build_nested_when_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_when_report(args: NestedWhenReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_when_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_when_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/one_armed_if/cli/workflow.rs b/packages/feature/lint-conditional/src/one_armed_if/cli/workflow.rs index 1fe5824a2..c9332bdc7 100644 --- a/packages/feature/lint-conditional/src/one_armed_if/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/one_armed_if/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::one_armed_if::cli::args::OneArmedIfReportArgs; use crate::one_armed_if::cli::render::print_one_armed_if_report; use crate::one_armed_if::usecase::{build_one_armed_if_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn one_armed_if_report(args: OneArmedIfReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_one_armed_if_report(file, dialect, &tree)?); + CliResult::Ok(build_one_armed_if_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/quoted_case_key/cli/workflow.rs b/packages/feature/lint-conditional/src/quoted_case_key/cli/workflow.rs index 886c53371..be696da0a 100644 --- a/packages/feature/lint-conditional/src/quoted_case_key/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/quoted_case_key/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::quoted_case_key::cli::args::QuotedCaseKeyReportArgs; use crate::quoted_case_key::cli::render::print_quoted_case_key_report; use crate::quoted_case_key::usecase::{ build_quoted_case_key_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn quoted_case_key_report(args: QuotedCaseKeyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_quoted_case_key_report(file, dialect, &tree)?); + CliResult::Ok(build_quoted_case_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/redundant_boolean_identity/cli/workflow.rs b/packages/feature/lint-conditional/src/redundant_boolean_identity/cli/workflow.rs index f9adf3924..74061d7cb 100644 --- a/packages/feature/lint-conditional/src/redundant_boolean_identity/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/redundant_boolean_identity/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_boolean_identity::cli::args::RedundantBooleanIdentityReportArgs; use crate::redundant_boolean_identity::cli::render::print_redundant_boolean_identity_report; use crate::redundant_boolean_identity::usecase::{ build_redundant_boolean_identity_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_boolean_identity_report( args: RedundantBooleanIdentityReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_boolean_identity_report( + CliResult::Ok(build_redundant_boolean_identity_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/redundant_if_nil/cli/workflow.rs b/packages/feature/lint-conditional/src/redundant_if_nil/cli/workflow.rs index 9bda2eea5..5079023e0 100644 --- a/packages/feature/lint-conditional/src/redundant_if_nil/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/redundant_if_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_if_nil::cli::args::RedundantIfNilReportArgs; use crate::redundant_if_nil::cli::render::print_redundant_if_nil_report; use crate::redundant_if_nil::usecase::{ build_redundant_if_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_if_nil_report(args: RedundantIfNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_if_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_if_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/single_clause_cond/cli/workflow.rs b/packages/feature/lint-conditional/src/single_clause_cond/cli/workflow.rs index 68b307c4e..460b2f0ed 100644 --- a/packages/feature/lint-conditional/src/single_clause_cond/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/single_clause_cond/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_clause_cond::cli::args::SingleClauseCondReportArgs; use crate::single_clause_cond::cli::render::print_single_clause_cond_report; use crate::single_clause_cond::usecase::{ build_single_clause_cond_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_clause_cond_report(args: SingleClauseCondReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_clause_cond_report(file, dialect, &tree)?); + CliResult::Ok(build_single_clause_cond_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/single_operand_boolean/cli/workflow.rs b/packages/feature/lint-conditional/src/single_operand_boolean/cli/workflow.rs index 1906b6f15..a7037cefe 100644 --- a/packages/feature/lint-conditional/src/single_operand_boolean/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/single_operand_boolean/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_operand_boolean::cli::args::SingleOperandBooleanReportArgs; use crate::single_operand_boolean::cli::render::print_single_operand_boolean_report; use crate::single_operand_boolean::usecase::{ build_single_operand_boolean_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_operand_boolean_report(args: SingleOperandBooleanReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_operand_boolean_report(file, dialect, &tree)?); + CliResult::Ok(build_single_operand_boolean_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/typecase_nil_key/cli/workflow.rs b/packages/feature/lint-conditional/src/typecase_nil_key/cli/workflow.rs index 91d7e960b..1d9c9c4e0 100644 --- a/packages/feature/lint-conditional/src/typecase_nil_key/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/typecase_nil_key/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::typecase_nil_key::cli::args::TypecaseNilKeyReportArgs; use crate::typecase_nil_key::cli::render::print_typecase_nil_key_report; use crate::typecase_nil_key::usecase::{ build_typecase_nil_key_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn typecase_nil_key_report(args: TypecaseNilKeyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_typecase_nil_key_report(file, dialect, &tree)?); + CliResult::Ok(build_typecase_nil_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/unreachable_case_clause/cli/workflow.rs b/packages/feature/lint-conditional/src/unreachable_case_clause/cli/workflow.rs index 9ac525fec..f0b87ad77 100644 --- a/packages/feature/lint-conditional/src/unreachable_case_clause/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/unreachable_case_clause/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unreachable_case_clause::cli::args::UnreachableCaseClauseReportArgs; use crate::unreachable_case_clause::cli::render::print_unreachable_case_clause_report; use crate::unreachable_case_clause::usecase::{ build_unreachable_case_clause_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn unreachable_case_clause_report(args: UnreachableCaseClauseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unreachable_case_clause_report(file, dialect, &tree)?); + CliResult::Ok(build_unreachable_case_clause_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/unreachable_cond_clause/cli/workflow.rs b/packages/feature/lint-conditional/src/unreachable_cond_clause/cli/workflow.rs index effd96374..e18e4dd91 100644 --- a/packages/feature/lint-conditional/src/unreachable_cond_clause/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/unreachable_cond_clause/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unreachable_cond_clause::cli::args::UnreachableCondClauseReportArgs; use crate::unreachable_cond_clause::cli::render::print_unreachable_cond_clause_report; use crate::unreachable_cond_clause::usecase::{ build_unreachable_cond_clause_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn unreachable_cond_clause_report(args: UnreachableCondClauseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unreachable_cond_clause_report(file, dialect, &tree)?); + CliResult::Ok(build_unreachable_cond_clause_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-conditional/src/when_unless_implicit_nil_misused/cli/workflow.rs b/packages/feature/lint-conditional/src/when_unless_implicit_nil_misused/cli/workflow.rs index f9c26fffa..88721c85c 100644 --- a/packages/feature/lint-conditional/src/when_unless_implicit_nil_misused/cli/workflow.rs +++ b/packages/feature/lint-conditional/src/when_unless_implicit_nil_misused/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::when_unless_implicit_nil_misused::cli::args::WhenUnlessImplicitNilMisusedReportArgs; use crate::when_unless_implicit_nil_misused::cli::render::print_when_unless_implicit_nil_misused_report; use crate::when_unless_implicit_nil_misused::usecase::{ build_when_unless_implicit_nil_misused_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn when_unless_implicit_nil_misused_report( args: WhenUnlessImplicitNilMisusedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_when_unless_implicit_nil_misused_report( + CliResult::Ok(build_when_unless_implicit_nil_misused_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/binds_constant/cli/workflow.rs b/packages/feature/lint-control-flow/src/binds_constant/cli/workflow.rs index 486c3ff28..c777752c9 100644 --- a/packages/feature/lint-control-flow/src/binds_constant/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/binds_constant/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::binds_constant::cli::args::BindsConstantReportArgs; use crate::binds_constant::cli::render::print_binds_constant_report; use crate::binds_constant::usecase::{ build_binds_constant_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn binds_constant_report(args: BindsConstantReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_binds_constant_report(file, dialect, &tree)?); + CliResult::Ok(build_binds_constant_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/block_name_shadows_outer_block/cli/workflow.rs b/packages/feature/lint-control-flow/src/block_name_shadows_outer_block/cli/workflow.rs index 157973c6e..122f0c503 100644 --- a/packages/feature/lint-control-flow/src/block_name_shadows_outer_block/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/block_name_shadows_outer_block/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::block_name_shadows_outer_block::cli::args::BlockNameShadowsOuterBlockReportArgs; use crate::block_name_shadows_outer_block::cli::render::print_block_name_shadows_outer_block_report; use crate::block_name_shadows_outer_block::usecase::{ build_block_name_shadows_outer_block_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn block_name_shadows_outer_block_report( args: BlockNameShadowsOuterBlockReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_block_name_shadows_outer_block_report( + CliResult::Ok(build_block_name_shadows_outer_block_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/dotimes_dolist_index_var_mutated/cli/workflow.rs b/packages/feature/lint-control-flow/src/dotimes_dolist_index_var_mutated/cli/workflow.rs index d797141c7..b6f0c61df 100644 --- a/packages/feature/lint-control-flow/src/dotimes_dolist_index_var_mutated/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/dotimes_dolist_index_var_mutated/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::dotimes_dolist_index_var_mutated::cli::args::DotimesDolistIndexVarMutatedReportArgs; use crate::dotimes_dolist_index_var_mutated::cli::render::print_dotimes_dolist_index_var_mutated_report; use crate::dotimes_dolist_index_var_mutated::usecase::{ build_dotimes_dolist_index_var_mutated_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn dotimes_dolist_index_var_mutated_report( args: DotimesDolistIndexVarMutatedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_dotimes_dolist_index_var_mutated_report( + CliResult::Ok(build_dotimes_dolist_index_var_mutated_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/eval_when_situation/cli/workflow.rs b/packages/feature/lint-control-flow/src/eval_when_situation/cli/workflow.rs index bc7e6ce03..a7576753e 100644 --- a/packages/feature/lint-control-flow/src/eval_when_situation/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/eval_when_situation/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eval_when_situation::cli::args::EvalWhenSituationReportArgs; use crate::eval_when_situation::cli::render::print_eval_when_situation_report; use crate::eval_when_situation::usecase::{ build_eval_when_situation_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eval_when_situation_report(args: EvalWhenSituationReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eval_when_situation_report(file, dialect, &tree)?); + CliResult::Ok(build_eval_when_situation_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/explicit_nil_return/cli/workflow.rs b/packages/feature/lint-control-flow/src/explicit_nil_return/cli/workflow.rs index 1da218490..d979fb1fd 100644 --- a/packages/feature/lint-control-flow/src/explicit_nil_return/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/explicit_nil_return/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::explicit_nil_return::cli::args::ExplicitNilReturnReportArgs; use crate::explicit_nil_return::cli::render::print_explicit_nil_return_report; use crate::explicit_nil_return::usecase::{ build_explicit_nil_return_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn explicit_nil_return_report(args: ExplicitNilReturnReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_explicit_nil_return_report(file, dialect, &tree)?); + CliResult::Ok(build_explicit_nil_return_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/go_to_undefined_tag/cli/workflow.rs b/packages/feature/lint-control-flow/src/go_to_undefined_tag/cli/workflow.rs index ed3496f9c..50beada59 100644 --- a/packages/feature/lint-control-flow/src/go_to_undefined_tag/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/go_to_undefined_tag/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::go_to_undefined_tag::cli::args::GoToUndefinedTagReportArgs; use crate::go_to_undefined_tag::cli::render::print_go_to_undefined_tag_report; use crate::go_to_undefined_tag::usecase::{ build_go_to_undefined_tag_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn go_to_undefined_tag_report(args: GoToUndefinedTagReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_go_to_undefined_tag_report(file, dialect, &tree)?); + CliResult::Ok(build_go_to_undefined_tag_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/handler_case_no_clauses/cli/workflow.rs b/packages/feature/lint-control-flow/src/handler_case_no_clauses/cli/workflow.rs index 51dc1fb6e..71ab93ed0 100644 --- a/packages/feature/lint-control-flow/src/handler_case_no_clauses/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/handler_case_no_clauses/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::handler_case_no_clauses::cli::args::HandlerCaseNoClausesReportArgs; use crate::handler_case_no_clauses::cli::render::print_handler_case_no_clauses_report; use crate::handler_case_no_clauses::usecase::{ build_handler_case_no_clauses_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn handler_case_no_clauses_report(args: HandlerCaseNoClausesReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_handler_case_no_clauses_report(file, dialect, &tree)?); + CliResult::Ok(build_handler_case_no_clauses_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/workflow.rs b/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/workflow.rs index 1e7949b3b..4345337d1 100644 --- a/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::malformed_iteration_spec::cli::args::MalformedIterationSpecReportArgs; use crate::malformed_iteration_spec::cli::render::print_malformed_iteration_spec_report; use crate::malformed_iteration_spec::usecase::{ build_malformed_iteration_spec_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn malformed_iteration_spec_report(args: MalformedIterationSpecReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_malformed_iteration_spec_report(file, dialect, &tree)?); + CliResult::Ok(build_malformed_iteration_spec_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/multiple_value_bind_all_ignored/cli/workflow.rs b/packages/feature/lint-control-flow/src/multiple_value_bind_all_ignored/cli/workflow.rs index a8289fca6..378a2c300 100644 --- a/packages/feature/lint-control-flow/src/multiple_value_bind_all_ignored/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/multiple_value_bind_all_ignored/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::multiple_value_bind_all_ignored::cli::args::MultipleValueBindAllIgnoredReportArgs; use crate::multiple_value_bind_all_ignored::cli::render::print_multiple_value_bind_all_ignored_report; use crate::multiple_value_bind_all_ignored::usecase::{ build_multiple_value_bind_all_ignored_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn multiple_value_bind_all_ignored_report( args: MultipleValueBindAllIgnoredReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_multiple_value_bind_all_ignored_report( + CliResult::Ok(build_multiple_value_bind_all_ignored_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/nested_progn/cli/workflow.rs b/packages/feature/lint-control-flow/src/nested_progn/cli/workflow.rs index a3c029c19..03f34182c 100644 --- a/packages/feature/lint-control-flow/src/nested_progn/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/nested_progn/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_progn::cli::args::NestedPrognReportArgs; use crate::nested_progn::cli::render::print_nested_progn_report; use crate::nested_progn::usecase::{build_nested_progn_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_progn_report(args: NestedPrognReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_progn_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_progn_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/prog2_to_progn/cli/workflow.rs b/packages/feature/lint-control-flow/src/prog2_to_progn/cli/workflow.rs index 790cae417..0d79e9c73 100644 --- a/packages/feature/lint-control-flow/src/prog2_to_progn/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/prog2_to_progn/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::prog2_to_progn::cli::args::Prog2ToPrognReportArgs; use crate::prog2_to_progn::cli::render::print_prog2_to_progn_report; use crate::prog2_to_progn::usecase::{ build_prog2_to_progn_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn prog2_to_progn_report(args: Prog2ToPrognReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_prog2_to_progn_report(file, dialect, &tree)?); + CliResult::Ok(build_prog2_to_progn_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/redundant_body_progn/cli/workflow.rs b/packages/feature/lint-control-flow/src/redundant_body_progn/cli/workflow.rs index 18eec43b7..a90209d03 100644 --- a/packages/feature/lint-control-flow/src/redundant_body_progn/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/redundant_body_progn/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_body_progn::cli::args::RedundantBodyPrognReportArgs; use crate::redundant_body_progn::cli::render::print_redundant_body_progn_report; use crate::redundant_body_progn::usecase::{ build_redundant_body_progn_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_body_progn_report(args: RedundantBodyPrognReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_body_progn_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_body_progn_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/redundant_prog1/cli/workflow.rs b/packages/feature/lint-control-flow/src/redundant_prog1/cli/workflow.rs index 76212aac4..38ad62e20 100644 --- a/packages/feature/lint-control-flow/src/redundant_prog1/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/redundant_prog1/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_prog1::cli::args::RedundantProg1ReportArgs; use crate::redundant_prog1::cli::render::print_redundant_prog1_report; use crate::redundant_prog1::usecase::{ build_redundant_prog1_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_prog1_report(args: RedundantProg1ReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_prog1_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_prog1_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/redundant_progn/cli/workflow.rs b/packages/feature/lint-control-flow/src/redundant_progn/cli/workflow.rs index 9fad8e9b3..bfbdf862c 100644 --- a/packages/feature/lint-control-flow/src/redundant_progn/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/redundant_progn/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_progn::cli::args::RedundantPrognReportArgs; use crate::redundant_progn::cli::render::print_redundant_progn_report; use crate::redundant_progn::usecase::{ build_redundant_progn_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_progn_report(args: RedundantPrognReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_progn_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_progn_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/return_from_unmatched_block/cli/workflow.rs b/packages/feature/lint-control-flow/src/return_from_unmatched_block/cli/workflow.rs index b3b8d6c02..9b3fdbe61 100644 --- a/packages/feature/lint-control-flow/src/return_from_unmatched_block/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/return_from_unmatched_block/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::return_from_unmatched_block::cli::args::ReturnFromUnmatchedBlockReportArgs; use crate::return_from_unmatched_block::cli::render::print_return_from_unmatched_block_report; use crate::return_from_unmatched_block::usecase::{ build_return_from_unmatched_block_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn return_from_unmatched_block_report( args: ReturnFromUnmatchedBlockReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_return_from_unmatched_block_report( + CliResult::Ok(build_return_from_unmatched_block_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/return_outside_implicit_nil_block/cli/workflow.rs b/packages/feature/lint-control-flow/src/return_outside_implicit_nil_block/cli/workflow.rs index b164aae38..49c292248 100644 --- a/packages/feature/lint-control-flow/src/return_outside_implicit_nil_block/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/return_outside_implicit_nil_block/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::return_outside_implicit_nil_block::cli::args::ReturnOutsideImplicitNilBlockReportArgs; use crate::return_outside_implicit_nil_block::cli::render::print_return_outside_implicit_nil_block_report; use crate::return_outside_implicit_nil_block::usecase::{ build_return_outside_implicit_nil_block_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn return_outside_implicit_nil_block_report( args: ReturnOutsideImplicitNilBlockReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_return_outside_implicit_nil_block_report( + CliResult::Ok(build_return_outside_implicit_nil_block_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/self_recursive_tail_call/cli/workflow.rs b/packages/feature/lint-control-flow/src/self_recursive_tail_call/cli/workflow.rs index 580b68b2d..488e04c29 100644 --- a/packages/feature/lint-control-flow/src/self_recursive_tail_call/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/self_recursive_tail_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::self_recursive_tail_call::cli::args::SelfRecursiveTailCallReportArgs; use crate::self_recursive_tail_call::cli::render::print_self_recursive_tail_call_report; @@ -6,18 +6,26 @@ use crate::self_recursive_tail_call::usecase::{ SelfRecursiveTailCallPolicyOptions, collect_self_recursive_tail_call, evaluate_self_recursive_tail_call_policy, summarize_self_recursive_tail_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn self_recursive_tail_call_report(args: SelfRecursiveTailCallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; + let analysis = analyze_files_raw(&files, |file| { + let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + CliResult::Ok(collect_self_recursive_tail_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + let mut scanned_form_count = 0; let mut violations = Vec::new(); - - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_self_recursive_tail_call(file, dialect, &tree)?; + for (file_form_count, file_violations) in analysis.succeeded { scanned_form_count += file_form_count; violations.extend(file_violations); } diff --git a/packages/feature/lint-control-flow/src/tagbody_unreachable_tag/cli/workflow.rs b/packages/feature/lint-control-flow/src/tagbody_unreachable_tag/cli/workflow.rs index f8353fcf7..36dd83962 100644 --- a/packages/feature/lint-control-flow/src/tagbody_unreachable_tag/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/tagbody_unreachable_tag/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::tagbody_unreachable_tag::cli::args::TagbodyUnreachableTagReportArgs; use crate::tagbody_unreachable_tag::cli::render::print_tagbody_unreachable_tag_report; use crate::tagbody_unreachable_tag::usecase::{ build_tagbody_unreachable_tag_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn tagbody_unreachable_tag_report(args: TagbodyUnreachableTagReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_tagbody_unreachable_tag_report(file, dialect, &tree)?); + CliResult::Ok(build_tagbody_unreachable_tag_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-control-flow/src/unwind_protect_no_cleanup/cli/workflow.rs b/packages/feature/lint-control-flow/src/unwind_protect_no_cleanup/cli/workflow.rs index 81712df31..a217a7460 100644 --- a/packages/feature/lint-control-flow/src/unwind_protect_no_cleanup/cli/workflow.rs +++ b/packages/feature/lint-control-flow/src/unwind_protect_no_cleanup/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unwind_protect_no_cleanup::cli::args::UnwindProtectNoCleanupReportArgs; use crate::unwind_protect_no_cleanup::cli::render::print_unwind_protect_no_cleanup_report; use crate::unwind_protect_no_cleanup::usecase::{ build_unwind_protect_no_cleanup_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn unwind_protect_no_cleanup_report(args: UnwindProtectNoCleanupReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unwind_protect_no_cleanup_report( + CliResult::Ok(build_unwind_protect_no_cleanup_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/butlast_default_count/cli/workflow.rs b/packages/feature/lint-form-shape/src/butlast_default_count/cli/workflow.rs index 454367f05..d6233944e 100644 --- a/packages/feature/lint-form-shape/src/butlast_default_count/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/butlast_default_count/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::butlast_default_count::cli::args::ButlastDefaultCountReportArgs; use crate::butlast_default_count::cli::render::print_butlast_default_count_report; use crate::butlast_default_count::usecase::{ build_butlast_default_count_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn butlast_default_count_report(args: ButlastDefaultCountReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_butlast_default_count_report(file, dialect, &tree)?); + CliResult::Ok(build_butlast_default_count_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/coerce_to_t/cli/workflow.rs b/packages/feature/lint-form-shape/src/coerce_to_t/cli/workflow.rs index 51f858781..455cf40ca 100644 --- a/packages/feature/lint-form-shape/src/coerce_to_t/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/coerce_to_t/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::coerce_to_t::cli::args::CoerceToTReportArgs; use crate::coerce_to_t::cli::render::print_coerce_to_t_report; use crate::coerce_to_t::usecase::{build_coerce_to_t_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn coerce_to_t_report(args: CoerceToTReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_coerce_to_t_report(file, dialect, &tree)?); + CliResult::Ok(build_coerce_to_t_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/defpackage_quoted/cli/workflow.rs b/packages/feature/lint-form-shape/src/defpackage_quoted/cli/workflow.rs index b98324125..3b59eb01f 100644 --- a/packages/feature/lint-form-shape/src/defpackage_quoted/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/defpackage_quoted/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::defpackage_quoted::cli::args::DefpackageQuotedReportArgs; use crate::defpackage_quoted::cli::render::print_defpackage_quoted_report; use crate::defpackage_quoted::usecase::{ build_defpackage_quoted_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn defpackage_quoted_report(args: DefpackageQuotedReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_defpackage_quoted_report(file, dialect, &tree)?); + CliResult::Ok(build_defpackage_quoted_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/destructuring_bind_unused_whole/cli/workflow.rs b/packages/feature/lint-form-shape/src/destructuring_bind_unused_whole/cli/workflow.rs index aee342ff0..5280e9086 100644 --- a/packages/feature/lint-form-shape/src/destructuring_bind_unused_whole/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/destructuring_bind_unused_whole/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::destructuring_bind_unused_whole::cli::args::DestructuringBindUnusedWholeReportArgs; use crate::destructuring_bind_unused_whole::cli::render::print_destructuring_bind_unused_whole_report; use crate::destructuring_bind_unused_whole::usecase::{ build_destructuring_bind_unused_whole_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn destructuring_bind_unused_whole_report( args: DestructuringBindUnusedWholeReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_destructuring_bind_unused_whole_report( + CliResult::Ok(build_destructuring_bind_unused_whole_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/duplicate_keyword/cli/workflow.rs b/packages/feature/lint-form-shape/src/duplicate_keyword/cli/workflow.rs index 1fe8dbf53..1f16fcb57 100644 --- a/packages/feature/lint-form-shape/src/duplicate_keyword/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/duplicate_keyword/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_keyword::cli::args::DuplicateKeywordReportArgs; use crate::duplicate_keyword::cli::render::print_duplicate_keyword_report; use crate::duplicate_keyword::usecase::{ build_duplicate_keyword_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_keyword_report(args: DuplicateKeywordReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_keyword_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_keyword_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/duplicate_lambda_list_keyword/cli/workflow.rs b/packages/feature/lint-form-shape/src/duplicate_lambda_list_keyword/cli/workflow.rs index 59914905c..8230368ed 100644 --- a/packages/feature/lint-form-shape/src/duplicate_lambda_list_keyword/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/duplicate_lambda_list_keyword/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_lambda_list_keyword::cli::args::DuplicateLambdaListKeywordReportArgs; use crate::duplicate_lambda_list_keyword::cli::render::print_duplicate_lambda_list_keyword_report; use crate::duplicate_lambda_list_keyword::usecase::{ build_duplicate_lambda_list_keyword_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_lambda_list_keyword_report( args: DuplicateLambdaListKeywordReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_lambda_list_keyword_report( + CliResult::Ok(build_duplicate_lambda_list_keyword_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/duplicate_let_bindings/cli/workflow.rs b/packages/feature/lint-form-shape/src/duplicate_let_bindings/cli/workflow.rs index 0c3755e22..d04392973 100644 --- a/packages/feature/lint-form-shape/src/duplicate_let_bindings/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/duplicate_let_bindings/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_let_bindings::cli::args::DuplicateLetBindingReportArgs; use crate::duplicate_let_bindings::cli::render::print_duplicate_let_binding_report; use crate::duplicate_let_bindings::usecase::{ build_duplicate_let_binding_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn duplicate_let_binding_report(args: DuplicateLetBindingReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_let_binding_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_let_binding_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/duplicate_parameters/cli/workflow.rs b/packages/feature/lint-form-shape/src/duplicate_parameters/cli/workflow.rs index 0a6240eee..54791d66d 100644 --- a/packages/feature/lint-form-shape/src/duplicate_parameters/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/duplicate_parameters/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_parameters::cli::args::DuplicateParameterReportArgs; use crate::duplicate_parameters::cli::render::print_duplicate_parameter_report; use crate::duplicate_parameters::usecase::{ build_duplicate_parameter_report, evaluate_fail_on_duplicate_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_parameter_report(args: DuplicateParameterReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_parameter_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_parameter_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_duplicate_policy(args.fail_on_duplicate, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/duplicate_setf_places/cli/workflow.rs b/packages/feature/lint-form-shape/src/duplicate_setf_places/cli/workflow.rs index 7af2401b7..c07b2056b 100644 --- a/packages/feature/lint-form-shape/src/duplicate_setf_places/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/duplicate_setf_places/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_setf_places::cli::args::DuplicateSetfPlaceReportArgs; use crate::duplicate_setf_places::cli::render::print_duplicate_setf_place_report; use crate::duplicate_setf_places::usecase::{ build_duplicate_setf_place_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_setf_place_report(args: DuplicateSetfPlaceReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_setf_place_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_setf_place_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/empty_let/cli/workflow.rs b/packages/feature/lint-form-shape/src/empty_let/cli/workflow.rs index 468fd8ebb..eaa8e6de6 100644 --- a/packages/feature/lint-form-shape/src/empty_let/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/empty_let/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::empty_let::cli::args::EmptyLetReportArgs; use crate::empty_let::cli::render::print_empty_let_report; use crate::empty_let::usecase::{build_empty_let_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn empty_let_report(args: EmptyLetReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_empty_let_report(file, dialect, &tree)?); + CliResult::Ok(build_empty_let_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/flet_single_use_inlinable/cli/workflow.rs b/packages/feature/lint-form-shape/src/flet_single_use_inlinable/cli/workflow.rs index 5d6b197b5..0ef65f68f 100644 --- a/packages/feature/lint-form-shape/src/flet_single_use_inlinable/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/flet_single_use_inlinable/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::flet_single_use_inlinable::cli::args::FletSingleUseInlinableReportArgs; use crate::flet_single_use_inlinable::cli::render::print_flet_single_use_inlinable_report; use crate::flet_single_use_inlinable::usecase::{ build_flet_single_use_inlinable_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn flet_single_use_inlinable_report(args: FletSingleUseInlinableReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_flet_single_use_inlinable_report( + CliResult::Ok(build_flet_single_use_inlinable_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/ftype_values_arity_mismatch/cli/workflow.rs b/packages/feature/lint-form-shape/src/ftype_values_arity_mismatch/cli/workflow.rs index 3f988788e..ff5c9df6b 100644 --- a/packages/feature/lint-form-shape/src/ftype_values_arity_mismatch/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/ftype_values_arity_mismatch/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::ftype_values_arity_mismatch::cli::args::FtypeValuesArityMismatchReportArgs; use crate::ftype_values_arity_mismatch::cli::render::print_ftype_values_arity_mismatch_report; use crate::ftype_values_arity_mismatch::usecase::{ build_ftype_values_arity_mismatch_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn ftype_values_arity_mismatch_report( args: FtypeValuesArityMismatchReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_ftype_values_arity_mismatch_report( + CliResult::Ok(build_ftype_values_arity_mismatch_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/funcall_lambda/cli/workflow.rs b/packages/feature/lint-form-shape/src/funcall_lambda/cli/workflow.rs index e42cd15cc..b0330cf01 100644 --- a/packages/feature/lint-form-shape/src/funcall_lambda/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/funcall_lambda/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::funcall_lambda::cli::args::FuncallLambdaReportArgs; use crate::funcall_lambda::cli::render::print_funcall_lambda_report; use crate::funcall_lambda::usecase::{ build_funcall_lambda_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn funcall_lambda_report(args: FuncallLambdaReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_funcall_lambda_report(file, dialect, &tree)?); + CliResult::Ok(build_funcall_lambda_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/getf_default_nil/cli/workflow.rs b/packages/feature/lint-form-shape/src/getf_default_nil/cli/workflow.rs index 3f02e1029..8663088e2 100644 --- a/packages/feature/lint-form-shape/src/getf_default_nil/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/getf_default_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::getf_default_nil::cli::args::GetfDefaultNilReportArgs; use crate::getf_default_nil::cli::render::print_getf_default_nil_report; use crate::getf_default_nil::usecase::{ build_getf_default_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn getf_default_nil_report(args: GetfDefaultNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_getf_default_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_getf_default_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/gethash_default/cli/workflow.rs b/packages/feature/lint-form-shape/src/gethash_default/cli/workflow.rs index bfcc8cc86..8606424b7 100644 --- a/packages/feature/lint-form-shape/src/gethash_default/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/gethash_default/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::gethash_default::cli::args::GethashDefaultReportArgs; use crate::gethash_default::cli::render::print_gethash_default_report; use crate::gethash_default::usecase::{ build_gethash_default_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn gethash_default_report(args: GethashDefaultReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_gethash_default_report(file, dialect, &tree)?); + CliResult::Ok(build_gethash_default_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/giant_conditional_form/cli/workflow.rs b/packages/feature/lint-form-shape/src/giant_conditional_form/cli/workflow.rs index 781e201bb..4870264e5 100644 --- a/packages/feature/lint-form-shape/src/giant_conditional_form/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/giant_conditional_form/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::giant_conditional_form::cli::args::GiantConditionalFormReportArgs; use crate::giant_conditional_form::cli::render::print_giant_conditional_form_report; @@ -6,18 +6,26 @@ use crate::giant_conditional_form::usecase::{ GiantConditionalFormPolicyOptions, collect_giant_conditional_form, evaluate_giant_conditional_form_policy, summarize_giant_conditional_form, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn giant_conditional_form_report(args: GiantConditionalFormReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; + let analysis = analyze_files_raw(&files, |file| { + let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + CliResult::Ok(collect_giant_conditional_form(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + let mut scanned_form_count = 0; let mut violations = Vec::new(); - - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_giant_conditional_form(file, dialect, &tree)?; + for (file_form_count, file_violations) in analysis.succeeded { scanned_form_count += file_form_count; violations.extend(file_violations); } diff --git a/packages/feature/lint-form-shape/src/lambda_list_keyword_order/cli/workflow.rs b/packages/feature/lint-form-shape/src/lambda_list_keyword_order/cli/workflow.rs index 3efaa91a0..83f710cec 100644 --- a/packages/feature/lint-form-shape/src/lambda_list_keyword_order/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/lambda_list_keyword_order/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::lambda_list_keyword_order::cli::args::LambdaListKeywordOrderReportArgs; use crate::lambda_list_keyword_order::cli::render::print_lambda_list_keyword_order_report; use crate::lambda_list_keyword_order::usecase::{ build_lambda_list_keyword_order_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn lambda_list_keyword_order_report(args: LambdaListKeywordOrderReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_lambda_list_keyword_order_report( + CliResult::Ok(build_lambda_list_keyword_order_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/loop_collect_into_immediately_returned/cli/workflow.rs b/packages/feature/lint-form-shape/src/loop_collect_into_immediately_returned/cli/workflow.rs index 3887ec849..45a2f4a57 100644 --- a/packages/feature/lint-form-shape/src/loop_collect_into_immediately_returned/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/loop_collect_into_immediately_returned/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::loop_collect_into_immediately_returned::cli::args::LoopCollectIntoImmediatelyReturnedReportArgs; use crate::loop_collect_into_immediately_returned::cli::render::print_loop_collect_into_immediately_returned_report; use crate::loop_collect_into_immediately_returned::usecase::{ build_loop_collect_into_immediately_returned_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn loop_collect_into_immediately_returned_report( args: LoopCollectIntoImmediatelyReturnedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_collect_into_immediately_returned_report( + CliResult::Ok(build_loop_collect_into_immediately_returned_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/make_array_default_keyword/cli/workflow.rs b/packages/feature/lint-form-shape/src/make_array_default_keyword/cli/workflow.rs index b3a3f664c..4d09c98d9 100644 --- a/packages/feature/lint-form-shape/src/make_array_default_keyword/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/make_array_default_keyword/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::make_array_default_keyword::cli::args::MakeArrayDefaultKeywordReportArgs; use crate::make_array_default_keyword::cli::render::print_make_array_default_keyword_report; use crate::make_array_default_keyword::usecase::{ build_make_array_default_keyword_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn make_array_default_keyword_report(args: MakeArrayDefaultKeywordReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_make_array_default_keyword_report( + CliResult::Ok(build_make_array_default_keyword_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/make_hash_table_test/cli/workflow.rs b/packages/feature/lint-form-shape/src/make_hash_table_test/cli/workflow.rs index 7758dfda6..c191c50d3 100644 --- a/packages/feature/lint-form-shape/src/make_hash_table_test/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/make_hash_table_test/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::make_hash_table_test::cli::args::MakeHashTableTestReportArgs; use crate::make_hash_table_test::cli::render::print_make_hash_table_test_report; use crate::make_hash_table_test::usecase::{ build_make_hash_table_test_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn make_hash_table_test_report(args: MakeHashTableTestReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_make_hash_table_test_report(file, dialect, &tree)?); + CliResult::Ok(build_make_hash_table_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/make_list_default_element/cli/workflow.rs b/packages/feature/lint-form-shape/src/make_list_default_element/cli/workflow.rs index fcb04352c..36e78adb6 100644 --- a/packages/feature/lint-form-shape/src/make_list_default_element/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/make_list_default_element/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::make_list_default_element::cli::args::MakeListDefaultElementReportArgs; use crate::make_list_default_element::cli::render::print_make_list_default_element_report; use crate::make_list_default_element::usecase::{ build_make_list_default_element_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn make_list_default_element_report(args: MakeListDefaultElementReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_make_list_default_element_report( + CliResult::Ok(build_make_list_default_element_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/malformed_let_binding/cli/workflow.rs b/packages/feature/lint-form-shape/src/malformed_let_binding/cli/workflow.rs index 4e9f2a6aa..191488f0a 100644 --- a/packages/feature/lint-form-shape/src/malformed_let_binding/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/malformed_let_binding/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::malformed_let_binding::cli::args::MalformedLetBindingReportArgs; use crate::malformed_let_binding::cli::render::print_malformed_let_binding_report; use crate::malformed_let_binding::usecase::{ build_malformed_let_binding_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn malformed_let_binding_report(args: MalformedLetBindingReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_malformed_let_binding_report(file, dialect, &tree)?); + CliResult::Ok(build_malformed_let_binding_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/manual_incf/cli/workflow.rs b/packages/feature/lint-form-shape/src/manual_incf/cli/workflow.rs index 15d92f3f1..364ed55a9 100644 --- a/packages/feature/lint-form-shape/src/manual_incf/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/manual_incf/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::manual_incf::cli::args::ManualIncfReportArgs; use crate::manual_incf::cli::render::print_manual_incf_report; use crate::manual_incf::usecase::{build_manual_incf_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn manual_incf_report(args: ManualIncfReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_manual_incf_report(file, dialect, &tree)?); + CliResult::Ok(build_manual_incf_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/manual_push/cli/workflow.rs b/packages/feature/lint-form-shape/src/manual_push/cli/workflow.rs index 2d17f1341..f5333782d 100644 --- a/packages/feature/lint-form-shape/src/manual_push/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/manual_push/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::manual_push::cli::args::ManualPushReportArgs; use crate::manual_push::cli::render::print_manual_push_report; use crate::manual_push::usecase::{build_manual_push_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn manual_push_report(args: ManualPushReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_manual_push_report(file, dialect, &tree)?); + CliResult::Ok(build_manual_push_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/manual_pushnew/cli/workflow.rs b/packages/feature/lint-form-shape/src/manual_pushnew/cli/workflow.rs index 9f5c8222d..7bbde5425 100644 --- a/packages/feature/lint-form-shape/src/manual_pushnew/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/manual_pushnew/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::manual_pushnew::cli::args::ManualPushnewReportArgs; use crate::manual_pushnew::cli::render::print_manual_pushnew_report; use crate::manual_pushnew::usecase::{ build_manual_pushnew_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn manual_pushnew_report(args: ManualPushnewReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_manual_pushnew_report(file, dialect, &tree)?); + CliResult::Ok(build_manual_pushnew_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/multiple_value_list_of_values/cli/workflow.rs b/packages/feature/lint-form-shape/src/multiple_value_list_of_values/cli/workflow.rs index f105d83df..b9118ce3b 100644 --- a/packages/feature/lint-form-shape/src/multiple_value_list_of_values/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/multiple_value_list_of_values/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::multiple_value_list_of_values::cli::args::MultipleValueListOfValuesReportArgs; use crate::multiple_value_list_of_values::cli::render::print_multiple_value_list_of_values_report; use crate::multiple_value_list_of_values::usecase::{ build_multiple_value_list_of_values_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn multiple_value_list_of_values_report( args: MultipleValueListOfValuesReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_multiple_value_list_of_values_report( + CliResult::Ok(build_multiple_value_list_of_values_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/multiple_value_setq_arity_mismatch/cli/workflow.rs b/packages/feature/lint-form-shape/src/multiple_value_setq_arity_mismatch/cli/workflow.rs index db1860f3d..1dc00677a 100644 --- a/packages/feature/lint-form-shape/src/multiple_value_setq_arity_mismatch/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/multiple_value_setq_arity_mismatch/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::multiple_value_setq_arity_mismatch::cli::args::MultipleValueSetqArityMismatchReportArgs; use crate::multiple_value_setq_arity_mismatch::cli::render::print_multiple_value_setq_arity_mismatch_report; use crate::multiple_value_setq_arity_mismatch::usecase::{ build_multiple_value_setq_arity_mismatch_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn multiple_value_setq_arity_mismatch_report( args: MultipleValueSetqArityMismatchReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_multiple_value_setq_arity_mismatch_report( + CliResult::Ok(build_multiple_value_setq_arity_mismatch_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/nested_char_case/cli/workflow.rs b/packages/feature/lint-form-shape/src/nested_char_case/cli/workflow.rs index 2b46816f2..334bde18e 100644 --- a/packages/feature/lint-form-shape/src/nested_char_case/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/nested_char_case/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_char_case::cli::args::NestedCharCaseReportArgs; use crate::nested_char_case::cli::render::print_nested_char_case_report; use crate::nested_char_case::usecase::{ build_nested_char_case_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_char_case_report(args: NestedCharCaseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_char_case_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_char_case_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/nested_cxr/cli/workflow.rs b/packages/feature/lint-form-shape/src/nested_cxr/cli/workflow.rs index b3a4695f7..1aada62b2 100644 --- a/packages/feature/lint-form-shape/src/nested_cxr/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/nested_cxr/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_cxr::cli::args::NestedCxrReportArgs; use crate::nested_cxr::cli::render::print_nested_cxr_report; use crate::nested_cxr::usecase::{build_nested_cxr_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_cxr_report(args: NestedCxrReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_cxr_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_cxr_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/package_level_shadowing/cli/workflow.rs b/packages/feature/lint-form-shape/src/package_level_shadowing/cli/workflow.rs index f9442f6bb..38cb895b4 100644 --- a/packages/feature/lint-form-shape/src/package_level_shadowing/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/package_level_shadowing/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::package_level_shadowing::cli::args::PackageLevelShadowingReportArgs; use crate::package_level_shadowing::cli::render::print_package_level_shadowing_report; @@ -6,18 +6,26 @@ use crate::package_level_shadowing::usecase::{ PackageLevelShadowingPolicyOptions, collect_package_level_shadowing, evaluate_package_level_shadowing_policy, summarize_package_level_shadowing, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn package_level_shadowing_report(args: PackageLevelShadowingReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; + let analysis = analyze_files_raw(&files, |file| { + let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + CliResult::Ok(collect_package_level_shadowing(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + let mut scanned_form_count = 0; let mut violations = Vec::new(); - - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_package_level_shadowing(file, dialect, &tree)?; + for (file_form_count, file_violations) in analysis.succeeded { scanned_form_count += file_form_count; violations.extend(file_violations); } diff --git a/packages/feature/lint-form-shape/src/parse_integer_default_radix/cli/workflow.rs b/packages/feature/lint-form-shape/src/parse_integer_default_radix/cli/workflow.rs index 44715fbc8..0a425dd66 100644 --- a/packages/feature/lint-form-shape/src/parse_integer_default_radix/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/parse_integer_default_radix/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::parse_integer_default_radix::cli::args::ParseIntegerDefaultRadixReportArgs; use crate::parse_integer_default_radix::cli::render::print_parse_integer_default_radix_report; use crate::parse_integer_default_radix::usecase::{ build_parse_integer_default_radix_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn parse_integer_default_radix_report( args: ParseIntegerDefaultRadixReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_parse_integer_default_radix_report( + CliResult::Ok(build_parse_integer_default_radix_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/quoted_form_contains_stray_unquote/cli/workflow.rs b/packages/feature/lint-form-shape/src/quoted_form_contains_stray_unquote/cli/workflow.rs index c4b864f03..d54409ae7 100644 --- a/packages/feature/lint-form-shape/src/quoted_form_contains_stray_unquote/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/quoted_form_contains_stray_unquote/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::quoted_form_contains_stray_unquote::cli::args::QuotedFormContainsStrayUnquoteReportArgs; use crate::quoted_form_contains_stray_unquote::cli::render::print_quoted_form_contains_stray_unquote_report; use crate::quoted_form_contains_stray_unquote::usecase::{ build_quoted_form_contains_stray_unquote_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn quoted_form_contains_stray_unquote_report( args: QuotedFormContainsStrayUnquoteReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_quoted_form_contains_stray_unquote_report( + CliResult::Ok(build_quoted_form_contains_stray_unquote_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_apply/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_apply/cli/workflow.rs index 94120e4d4..d19733056 100644 --- a/packages/feature/lint-form-shape/src/redundant_apply/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_apply/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_apply::cli::args::RedundantApplyReportArgs; use crate::redundant_apply::cli::render::print_redundant_apply_report; use crate::redundant_apply::usecase::{ build_redundant_apply_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_apply_report(args: RedundantApplyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_apply_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_apply_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_funcall/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_funcall/cli/workflow.rs index 56af0c8d9..d7f3995cb 100644 --- a/packages/feature/lint-form-shape/src/redundant_funcall/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_funcall/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_funcall::cli::args::RedundantFuncallReportArgs; use crate::redundant_funcall::cli::render::print_redundant_funcall_report; use crate::redundant_funcall::usecase::{ build_redundant_funcall_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_funcall_report(args: RedundantFuncallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_funcall_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_funcall_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_identity/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_identity/cli/workflow.rs index 459664db6..cb8cf8503 100644 --- a/packages/feature/lint-form-shape/src/redundant_identity/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_identity/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_identity::cli::args::RedundantIdentityReportArgs; use crate::redundant_identity::cli::render::print_redundant_identity_report; use crate::redundant_identity::usecase::{ build_redundant_identity_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_identity_report(args: RedundantIdentityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_identity_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_identity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_let_star/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_let_star/cli/workflow.rs index e82e8b5ef..e96718dc1 100644 --- a/packages/feature/lint-form-shape/src/redundant_let_star/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_let_star/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_let_star::cli::args::RedundantLetStarReportArgs; use crate::redundant_let_star::cli::render::print_redundant_let_star_report; use crate::redundant_let_star::usecase::{ build_redundant_let_star_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_let_star_report(args: RedundantLetStarReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_let_star_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_let_star_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_quote/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_quote/cli/workflow.rs index 711b6d82a..5c83e4696 100644 --- a/packages/feature/lint-form-shape/src/redundant_quote/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_quote/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_quote::cli::args::RedundantQuoteReportArgs; use crate::redundant_quote::cli::render::print_redundant_quote_report; use crate::redundant_quote::usecase::{ build_redundant_quote_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_quote_report(args: RedundantQuoteReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_quote_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_quote_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/redundant_the/cli/workflow.rs b/packages/feature/lint-form-shape/src/redundant_the/cli/workflow.rs index 1ebd8b999..df010623c 100644 --- a/packages/feature/lint-form-shape/src/redundant_the/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/redundant_the/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_the::cli::args::RedundantTheReportArgs; use crate::redundant_the::cli::render::print_redundant_the_report; use crate::redundant_the::usecase::{ build_redundant_the_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_the_report(args: RedundantTheReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_the_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_the_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/self_assignment/cli/workflow.rs b/packages/feature/lint-form-shape/src/self_assignment/cli/workflow.rs index 5407537c6..07448088e 100644 --- a/packages/feature/lint-form-shape/src/self_assignment/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/self_assignment/cli/workflow.rs @@ -1,20 +1,26 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::self_assignment::cli::args::SelfAssignmentReportArgs; use crate::self_assignment::cli::render::print_self_assignment_report; use crate::self_assignment::usecase::{ build_self_assignment_report, evaluate_fail_on_self_assignment_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn self_assignment_report(args: SelfAssignmentReportArgs) -> CommandResult { // Explicit files only: this command has never expanded a directory // argument, and the envelope does not change what it accepts. - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_self_assignment_report(file, dialect, &tree)?); + CliResult::Ok(build_self_assignment_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_self_assignment_policy(args.fail_on_self_assignment, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/setf_arity/cli/workflow.rs b/packages/feature/lint-form-shape/src/setf_arity/cli/workflow.rs index b2bdcf701..18743cd69 100644 --- a/packages/feature/lint-form-shape/src/setf_arity/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/setf_arity/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::setf_arity::cli::args::SetfArityReportArgs; use crate::setf_arity::cli::render::print_setf_arity_report; use crate::setf_arity::usecase::{build_setf_arity_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn setf_arity_report(args: SetfArityReportArgs) -> CommandResult { // Explicit files only: this command has never expanded a directory // argument, and the envelope does not change what it accepts. - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_setf_arity_report(file, dialect, &tree)?); + CliResult::Ok(build_setf_arity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/setq_non_variable/cli/workflow.rs b/packages/feature/lint-form-shape/src/setq_non_variable/cli/workflow.rs index 704456c68..1bfdde790 100644 --- a/packages/feature/lint-form-shape/src/setq_non_variable/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/setq_non_variable/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::setq_non_variable::cli::args::SetqNonVariableReportArgs; use crate::setq_non_variable::cli::render::print_setq_non_variable_report; use crate::setq_non_variable::usecase::{ build_setq_non_variable_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn setq_non_variable_report(args: SetqNonVariableReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_setq_non_variable_report(file, dialect, &tree)?); + CliResult::Ok(build_setq_non_variable_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/sharp_quoted_lambda/cli/workflow.rs b/packages/feature/lint-form-shape/src/sharp_quoted_lambda/cli/workflow.rs index 89a8d18b5..776ce70bd 100644 --- a/packages/feature/lint-form-shape/src/sharp_quoted_lambda/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/sharp_quoted_lambda/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::sharp_quoted_lambda::cli::args::SharpQuotedLambdaReportArgs; use crate::sharp_quoted_lambda::cli::render::print_sharp_quoted_lambda_report; use crate::sharp_quoted_lambda::usecase::{ build_sharp_quoted_lambda_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn sharp_quoted_lambda_report(args: SharpQuotedLambdaReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_sharp_quoted_lambda_report(file, dialect, &tree)?); + CliResult::Ok(build_sharp_quoted_lambda_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/single_value_bind/cli/workflow.rs b/packages/feature/lint-form-shape/src/single_value_bind/cli/workflow.rs index 674e0141c..e51a9c229 100644 --- a/packages/feature/lint-form-shape/src/single_value_bind/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/single_value_bind/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_value_bind::cli::args::SingleValueBindReportArgs; use crate::single_value_bind::cli::render::print_single_value_bind_report; use crate::single_value_bind::usecase::{ build_single_value_bind_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_value_bind_report(args: SingleValueBindReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_value_bind_report(file, dialect, &tree)?); + CliResult::Ok(build_single_value_bind_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/the_arity/cli/workflow.rs b/packages/feature/lint-form-shape/src/the_arity/cli/workflow.rs index 30b1d86f4..5953d74a8 100644 --- a/packages/feature/lint-form-shape/src/the_arity/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/the_arity/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::the_arity::cli::args::TheArityReportArgs; use crate::the_arity::cli::render::print_the_arity_report; use crate::the_arity::usecase::{build_the_arity_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn the_arity_report(args: TheArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_the_arity_report(file, dialect, &tree)?); + CliResult::Ok(build_the_arity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/typep_predicate/cli/workflow.rs b/packages/feature/lint-form-shape/src/typep_predicate/cli/workflow.rs index 9ccfa40be..7df24795b 100644 --- a/packages/feature/lint-form-shape/src/typep_predicate/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/typep_predicate/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::typep_predicate::cli::args::TypepPredicateReportArgs; use crate::typep_predicate::cli::render::print_typep_predicate_report; use crate::typep_predicate::usecase::{ build_typep_predicate_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn typep_predicate_report(args: TypepPredicateReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_typep_predicate_report(file, dialect, &tree)?); + CliResult::Ok(build_typep_predicate_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/values_list_of_list/cli/workflow.rs b/packages/feature/lint-form-shape/src/values_list_of_list/cli/workflow.rs index ecaa8f320..8ad6266c8 100644 --- a/packages/feature/lint-form-shape/src/values_list_of_list/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/values_list_of_list/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::values_list_of_list::cli::args::ValuesListOfListReportArgs; use crate::values_list_of_list::cli::render::print_values_list_of_list_report; use crate::values_list_of_list::usecase::{ build_values_list_of_list_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn values_list_of_list_report(args: ValuesListOfListReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_values_list_of_list_report(file, dialect, &tree)?); + CliResult::Ok(build_values_list_of_list_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/with_accessors_empty_binding_list/cli/workflow.rs b/packages/feature/lint-form-shape/src/with_accessors_empty_binding_list/cli/workflow.rs index 45c5640a3..1dfda654c 100644 --- a/packages/feature/lint-form-shape/src/with_accessors_empty_binding_list/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/with_accessors_empty_binding_list/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::with_accessors_empty_binding_list::cli::args::WithAccessorsEmptyBindingListReportArgs; use crate::with_accessors_empty_binding_list::cli::render::print_with_accessors_empty_binding_list_report; use crate::with_accessors_empty_binding_list::usecase::{ build_with_accessors_empty_binding_list_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn with_accessors_empty_binding_list_report( args: WithAccessorsEmptyBindingListReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_with_accessors_empty_binding_list_report( + CliResult::Ok(build_with_accessors_empty_binding_list_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-form-shape/src/with_open_file_redundant_direction_default/cli/workflow.rs b/packages/feature/lint-form-shape/src/with_open_file_redundant_direction_default/cli/workflow.rs index 1a3e5896a..1fe728d53 100644 --- a/packages/feature/lint-form-shape/src/with_open_file_redundant_direction_default/cli/workflow.rs +++ b/packages/feature/lint-form-shape/src/with_open_file_redundant_direction_default/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::with_open_file_redundant_direction_default::cli::args::WithOpenFileRedundantDirectionDefaultReportArgs; use crate::with_open_file_redundant_direction_default::cli::render::print_with_open_file_redundant_direction_default_report; use crate::with_open_file_redundant_direction_default::usecase::{ build_with_open_file_redundant_direction_default_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn with_open_file_redundant_direction_default_report( args: WithOpenFileRedundantDirectionDefaultReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_with_open_file_redundant_direction_default_report( + CliResult::Ok(build_with_open_file_redundant_direction_default_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-introspection/src/intern_dynamic_package_target/cli/workflow.rs b/packages/feature/lint-introspection/src/intern_dynamic_package_target/cli/workflow.rs index b01bf8cad..b8890f497 100644 --- a/packages/feature/lint-introspection/src/intern_dynamic_package_target/cli/workflow.rs +++ b/packages/feature/lint-introspection/src/intern_dynamic_package_target/cli/workflow.rs @@ -1,6 +1,9 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; use crate::intern_dynamic_package_target::cli::args::InternDynamicPackageTargetReportArgs; use crate::intern_dynamic_package_target::cli::render::print_intern_dynamic_package_target_report; @@ -13,13 +16,17 @@ pub fn intern_dynamic_package_target_report( ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_intern_dynamic_package_target_report( + CliResult::Ok(build_intern_dynamic_package_target_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-introspection/src/introspection_probe_unchecked/cli/workflow.rs b/packages/feature/lint-introspection/src/introspection_probe_unchecked/cli/workflow.rs index c4009c4c7..0222d2c02 100644 --- a/packages/feature/lint-introspection/src/introspection_probe_unchecked/cli/workflow.rs +++ b/packages/feature/lint-introspection/src/introspection_probe_unchecked/cli/workflow.rs @@ -1,6 +1,9 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; use crate::introspection_probe_unchecked::cli::args::IntrospectionProbeUncheckedReportArgs; use crate::introspection_probe_unchecked::cli::render::print_introspection_probe_unchecked_report; @@ -13,13 +16,17 @@ pub fn introspection_probe_unchecked_report( ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_introspection_probe_unchecked_report( + CliResult::Ok(build_introspection_probe_unchecked_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-introspection/src/symbol_function_fset_dynamic_name/cli/workflow.rs b/packages/feature/lint-introspection/src/symbol_function_fset_dynamic_name/cli/workflow.rs index 87fea09be..f74fbd92b 100644 --- a/packages/feature/lint-introspection/src/symbol_function_fset_dynamic_name/cli/workflow.rs +++ b/packages/feature/lint-introspection/src/symbol_function_fset_dynamic_name/cli/workflow.rs @@ -1,6 +1,9 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; use crate::symbol_function_fset_dynamic_name::cli::args::SymbolFunctionFsetDynamicNameReportArgs; use crate::symbol_function_fset_dynamic_name::cli::render::print_symbol_function_fset_dynamic_name_report; @@ -13,13 +16,17 @@ pub fn symbol_function_fset_dynamic_name_report( ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_symbol_function_fset_dynamic_name_report( + CliResult::Ok(build_symbol_function_fset_dynamic_name_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/dolist_result_form_references_loop_variable/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/dolist_result_form_references_loop_variable/cli/workflow.rs index fa1018f20..98d0ee831 100644 --- a/packages/feature/lint-iteration-flow/src/dolist_result_form_references_loop_variable/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/dolist_result_form_references_loop_variable/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::dolist_result_form_references_loop_variable::cli::args::DolistResultFormReferencesLoopVariableReportArgs; use crate::dolist_result_form_references_loop_variable::cli::render::print_dolist_result_form_references_loop_variable_report; use crate::dolist_result_form_references_loop_variable::usecase::{ build_dolist_result_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn dolist_result_form_references_loop_variable_report( args: DolistResultFormReferencesLoopVariableReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_dolist_result_report(file, dialect, &tree)?); + CliResult::Ok(build_dolist_result_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/dotimes_bound_mutation_has_no_effect/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/dotimes_bound_mutation_has_no_effect/cli/workflow.rs index 5b73ae6b0..8849f5ae0 100644 --- a/packages/feature/lint-iteration-flow/src/dotimes_bound_mutation_has_no_effect/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/dotimes_bound_mutation_has_no_effect/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::dotimes_bound_mutation_has_no_effect::cli::args::DotimesBoundMutationHasNoEffectReportArgs; use crate::dotimes_bound_mutation_has_no_effect::cli::render::print_dotimes_bound_mutation_has_no_effect_report; use crate::dotimes_bound_mutation_has_no_effect::usecase::{ build_dotimes_bound_mutation_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn dotimes_bound_mutation_has_no_effect_report( args: DotimesBoundMutationHasNoEffectReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_dotimes_bound_mutation_report(file, dialect, &tree)?); + CliResult::Ok(build_dotimes_bound_mutation_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/loop_clause_order_violation/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/loop_clause_order_violation/cli/workflow.rs index 92114080c..ca732a70c 100644 --- a/packages/feature/lint-iteration-flow/src/loop_clause_order_violation/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/loop_clause_order_violation/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::loop_clause_order_violation::cli::args::LoopClauseOrderViolationReportArgs; use crate::loop_clause_order_violation::cli::render::print_loop_clause_order_violation_report; use crate::loop_clause_order_violation::usecase::{ build_loop_clause_order_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn loop_clause_order_violation_report( args: LoopClauseOrderViolationReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_clause_order_report(file, dialect, &tree)?); + CliResult::Ok(build_loop_clause_order_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/loop_for_across_statically_known_list/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/loop_for_across_statically_known_list/cli/workflow.rs index 37e6a7c44..522fbff0f 100644 --- a/packages/feature/lint-iteration-flow/src/loop_for_across_statically_known_list/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/loop_for_across_statically_known_list/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::loop_for_across_statically_known_list::cli::args::LoopForAcrossStaticallyKnownListReportArgs; use crate::loop_for_across_statically_known_list::cli::render::print_loop_for_across_statically_known_list_report; use crate::loop_for_across_statically_known_list::usecase::{ build_loop_for_across_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn loop_for_across_statically_known_list_report( args: LoopForAcrossStaticallyKnownListReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_for_across_report(file, dialect, &tree)?); + CliResult::Ok(build_loop_for_across_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/loop_into_accumulator_kind_conflict/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/loop_into_accumulator_kind_conflict/cli/workflow.rs index 52e44ca79..53807e763 100644 --- a/packages/feature/lint-iteration-flow/src/loop_into_accumulator_kind_conflict/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/loop_into_accumulator_kind_conflict/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::loop_into_accumulator_kind_conflict::cli::args::LoopIntoAccumulatorKindConflictReportArgs; use crate::loop_into_accumulator_kind_conflict::cli::render::print_loop_into_accumulator_kind_conflict_report; use crate::loop_into_accumulator_kind_conflict::usecase::{ build_loop_accumulator_conflict_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn loop_into_accumulator_kind_conflict_report( args: LoopIntoAccumulatorKindConflictReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_accumulator_conflict_report( + CliResult::Ok(build_loop_accumulator_conflict_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-iteration-flow/src/loop_unreachable_finally_clause/cli/workflow.rs b/packages/feature/lint-iteration-flow/src/loop_unreachable_finally_clause/cli/workflow.rs index 8a6aa42c1..c641cd09c 100644 --- a/packages/feature/lint-iteration-flow/src/loop_unreachable_finally_clause/cli/workflow.rs +++ b/packages/feature/lint-iteration-flow/src/loop_unreachable_finally_clause/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::loop_unreachable_finally_clause::cli::args::LoopUnreachableFinallyClauseReportArgs; use crate::loop_unreachable_finally_clause::cli::render::print_loop_unreachable_finally_clause_report; use crate::loop_unreachable_finally_clause::usecase::{ build_loop_unreachable_finally_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn loop_unreachable_finally_clause_report( args: LoopUnreachableFinallyClauseReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_unreachable_finally_report(file, dialect, &tree)?); + CliResult::Ok(build_loop_unreachable_finally_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/division_result_precision_loss/cli/workflow.rs b/packages/feature/lint-numeric/src/division_result_precision_loss/cli/workflow.rs index 860484bdb..f55d74d36 100644 --- a/packages/feature/lint-numeric/src/division_result_precision_loss/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/division_result_precision_loss/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::division_result_precision_loss::cli::args::DivisionResultPrecisionLossReportArgs; use crate::division_result_precision_loss::cli::render::print_division_result_precision_loss_report; use crate::division_result_precision_loss::usecase::{ build_division_result_precision_loss_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn division_result_precision_loss_report( args: DivisionResultPrecisionLossReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_division_result_precision_loss_report( + CliResult::Ok(build_division_result_precision_loss_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/epsilon_less_float_loop_bound/cli/workflow.rs b/packages/feature/lint-numeric/src/epsilon_less_float_loop_bound/cli/workflow.rs index 214f596b0..b4f9e6fe0 100644 --- a/packages/feature/lint-numeric/src/epsilon_less_float_loop_bound/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/epsilon_less_float_loop_bound/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::epsilon_less_float_loop_bound::cli::args::EpsilonLessFloatLoopBoundReportArgs; use crate::epsilon_less_float_loop_bound::cli::render::print_epsilon_less_float_loop_bound_report; use crate::epsilon_less_float_loop_bound::usecase::{ build_epsilon_less_float_loop_bound_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn epsilon_less_float_loop_bound_report( args: EpsilonLessFloatLoopBoundReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_epsilon_less_float_loop_bound_report( + CliResult::Ok(build_epsilon_less_float_loop_bound_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/eq_char_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/eq_char_comparison/cli/workflow.rs index 79b557d4f..6026920e3 100644 --- a/packages/feature/lint-numeric/src/eq_char_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/eq_char_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eq_char_comparison::cli::args::EqCharComparisonReportArgs; use crate::eq_char_comparison::cli::render::print_eq_char_comparison_report; use crate::eq_char_comparison::usecase::{ build_eq_char_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eq_char_comparison_report(args: EqCharComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eq_char_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_eq_char_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/eq_number_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/eq_number_comparison/cli/workflow.rs index b66efe3d7..55a673e8f 100644 --- a/packages/feature/lint-numeric/src/eq_number_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/eq_number_comparison/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eq_number_comparison::cli::args::EqNumberComparisonReportArgs; use crate::eq_number_comparison::cli::render::print_eq_number_comparison_report; use crate::eq_number_comparison::usecase::{ build_eq_number_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn eq_number_comparison_report(args: EqNumberComparisonReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eq_number_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_eq_number_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/eql_list_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/eql_list_comparison/cli/workflow.rs index cb974394e..980982f44 100644 --- a/packages/feature/lint-numeric/src/eql_list_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/eql_list_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eql_list_comparison::cli::args::EqlListComparisonReportArgs; use crate::eql_list_comparison::cli::render::print_eql_list_comparison_report; use crate::eql_list_comparison::usecase::{ build_eql_list_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eql_list_comparison_report(args: EqlListComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eql_list_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_eql_list_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/eql_string_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/eql_string_comparison/cli/workflow.rs index 56699d9fd..5892323f9 100644 --- a/packages/feature/lint-numeric/src/eql_string_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/eql_string_comparison/cli/workflow.rs @@ -1,18 +1,24 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eql_string_comparison::cli::args::EqlStringComparisonReportArgs; use crate::eql_string_comparison::cli::render::print_eql_string_comparison_report; use crate::eql_string_comparison::usecase::{ build_eql_string_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn eql_string_comparison_report(args: EqlStringComparisonReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eql_string_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_eql_string_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/equality_arity/cli/workflow.rs b/packages/feature/lint-numeric/src/equality_arity/cli/workflow.rs index 5cd12e7c6..a22eae450 100644 --- a/packages/feature/lint-numeric/src/equality_arity/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/equality_arity/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::equality_arity::cli::args::EqualityArityReportArgs; use crate::equality_arity::cli::render::print_equality_arity_report; use crate::equality_arity::usecase::{ build_equality_arity_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn equality_arity_report(args: EqualityArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_equality_arity_report(file, dialect, &tree)?); + CliResult::Ok(build_equality_arity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/explicit_step_delta/cli/workflow.rs b/packages/feature/lint-numeric/src/explicit_step_delta/cli/workflow.rs index d8998349a..e0983637e 100644 --- a/packages/feature/lint-numeric/src/explicit_step_delta/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/explicit_step_delta/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::explicit_step_delta::cli::args::ExplicitStepDeltaReportArgs; use crate::explicit_step_delta::cli::render::print_explicit_step_delta_report; use crate::explicit_step_delta::usecase::{ build_explicit_step_delta_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn explicit_step_delta_report(args: ExplicitStepDeltaReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_explicit_step_delta_report(file, dialect, &tree)?); + CliResult::Ok(build_explicit_step_delta_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/identity_arithmetic/cli/workflow.rs b/packages/feature/lint-numeric/src/identity_arithmetic/cli/workflow.rs index ca63b2127..9a934e98a 100644 --- a/packages/feature/lint-numeric/src/identity_arithmetic/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/identity_arithmetic/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::identity_arithmetic::cli::args::IdentityArithmeticReportArgs; use crate::identity_arithmetic::cli::render::print_identity_arithmetic_report; use crate::identity_arithmetic::usecase::{ build_identity_arithmetic_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn identity_arithmetic_report(args: IdentityArithmeticReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_identity_arithmetic_report(file, dialect, &tree)?); + CliResult::Ok(build_identity_arithmetic_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/literal_place/cli/workflow.rs b/packages/feature/lint-numeric/src/literal_place/cli/workflow.rs index db4e7bed7..8af7b3b94 100644 --- a/packages/feature/lint-numeric/src/literal_place/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/literal_place/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::literal_place::cli::args::LiteralPlaceReportArgs; use crate::literal_place::cli::render::print_literal_place_report; use crate::literal_place::usecase::{ build_literal_place_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn literal_place_report(args: LiteralPlaceReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_literal_place_report(file, dialect, &tree)?); + CliResult::Ok(build_literal_place_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/mixed_float_precision_arithmetic/cli/workflow.rs b/packages/feature/lint-numeric/src/mixed_float_precision_arithmetic/cli/workflow.rs index e7b569f8b..d060a987f 100644 --- a/packages/feature/lint-numeric/src/mixed_float_precision_arithmetic/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/mixed_float_precision_arithmetic/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::mixed_float_precision_arithmetic::cli::args::MixedFloatPrecisionArithmeticReportArgs; use crate::mixed_float_precision_arithmetic::cli::render::print_mixed_float_precision_arithmetic_report; use crate::mixed_float_precision_arithmetic::usecase::{ build_mixed_float_precision_arithmetic_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn mixed_float_precision_arithmetic_report( args: MixedFloatPrecisionArithmeticReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_mixed_float_precision_arithmetic_report( + CliResult::Ok(build_mixed_float_precision_arithmetic_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/modify_macro_arity/cli/workflow.rs b/packages/feature/lint-numeric/src/modify_macro_arity/cli/workflow.rs index 3ba3da90d..fa102b06d 100644 --- a/packages/feature/lint-numeric/src/modify_macro_arity/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/modify_macro_arity/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::modify_macro_arity::cli::args::ModifyMacroArityReportArgs; use crate::modify_macro_arity::cli::render::print_modify_macro_arity_report; use crate::modify_macro_arity::usecase::{ build_modify_macro_arity_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn modify_macro_arity_report(args: ModifyMacroArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_modify_macro_arity_report(file, dialect, &tree)?); + CliResult::Ok(build_modify_macro_arity_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/negated_step_delta/cli/workflow.rs b/packages/feature/lint-numeric/src/negated_step_delta/cli/workflow.rs index 773ec2261..acaa150ac 100644 --- a/packages/feature/lint-numeric/src/negated_step_delta/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/negated_step_delta/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::negated_step_delta::cli::args::NegatedStepDeltaReportArgs; use crate::negated_step_delta::cli::render::print_negated_step_delta_report; use crate::negated_step_delta::usecase::{ build_negated_step_delta_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn negated_step_delta_report(args: NegatedStepDeltaReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_negated_step_delta_report(file, dialect, &tree)?); + CliResult::Ok(build_negated_step_delta_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/nil_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/nil_comparison/cli/workflow.rs index ee920fd27..6edd7640c 100644 --- a/packages/feature/lint-numeric/src/nil_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/nil_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nil_comparison::cli::args::NilComparisonReportArgs; use crate::nil_comparison::cli::render::print_nil_comparison_report; use crate::nil_comparison::usecase::{ build_nil_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nil_comparison_report(args: NilComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nil_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_nil_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/one_step_arithmetic/cli/workflow.rs b/packages/feature/lint-numeric/src/one_step_arithmetic/cli/workflow.rs index 91353e48e..04c62b165 100644 --- a/packages/feature/lint-numeric/src/one_step_arithmetic/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/one_step_arithmetic/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::one_step_arithmetic::cli::args::OneStepArithmeticReportArgs; use crate::one_step_arithmetic::cli::render::print_one_step_arithmetic_report; use crate::one_step_arithmetic::usecase::{ build_one_step_arithmetic_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn one_step_arithmetic_report(args: OneStepArithmeticReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_one_step_arithmetic_report(file, dialect, &tree)?); + CliResult::Ok(build_one_step_arithmetic_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/redundant_divisor/cli/workflow.rs b/packages/feature/lint-numeric/src/redundant_divisor/cli/workflow.rs index c2774d57a..83800d1df 100644 --- a/packages/feature/lint-numeric/src/redundant_divisor/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/redundant_divisor/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_divisor::cli::args::RedundantDivisorReportArgs; use crate::redundant_divisor::cli::render::print_redundant_divisor_report; use crate::redundant_divisor::usecase::{ build_redundant_divisor_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_divisor_report(args: RedundantDivisorReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_divisor_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_divisor_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/redundant_precision_coercion/cli/workflow.rs b/packages/feature/lint-numeric/src/redundant_precision_coercion/cli/workflow.rs index e7aff105c..ef4af5ebc 100644 --- a/packages/feature/lint-numeric/src/redundant_precision_coercion/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/redundant_precision_coercion/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_precision_coercion::cli::args::RedundantPrecisionCoercionReportArgs; use crate::redundant_precision_coercion::cli::render::print_redundant_precision_coercion_report; use crate::redundant_precision_coercion::usecase::{ build_redundant_precision_coercion_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_precision_coercion_report( args: RedundantPrecisionCoercionReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_precision_coercion_report( + CliResult::Ok(build_redundant_precision_coercion_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/self_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/self_comparison/cli/workflow.rs index 34a7595fd..41737e1f7 100644 --- a/packages/feature/lint-numeric/src/self_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/self_comparison/cli/workflow.rs @@ -1,21 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::self_comparison::cli::args::SelfComparisonReportArgs; use crate::self_comparison::cli::render::print_self_comparison_report; use crate::self_comparison::usecase::{ build_self_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn self_comparison_report(args: SelfComparisonReportArgs) -> CommandResult { // This command takes files, not directories: it never grew the directory // expansion its siblings have, and adding it here would be a user-visible // change of scope rather than a move onto the shared envelope. - let mut reports = Vec::with_capacity(args.files.len()); - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_self_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_self_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/sign_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/sign_comparison/cli/workflow.rs index bd3385996..13f1e5af4 100644 --- a/packages/feature/lint-numeric/src/sign_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/sign_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::sign_comparison::cli::args::SignComparisonReportArgs; use crate::sign_comparison::cli::render::print_sign_comparison_report; use crate::sign_comparison::usecase::{ build_sign_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn sign_comparison_report(args: SignComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_sign_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_sign_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/single_arg_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/single_arg_comparison/cli/workflow.rs index 22204ad21..93a56e745 100644 --- a/packages/feature/lint-numeric/src/single_arg_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/single_arg_comparison/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_arg_comparison::cli::args::SingleArgComparisonReportArgs; use crate::single_arg_comparison::cli::render::print_single_arg_comparison_report; use crate::single_arg_comparison::usecase::{ build_single_arg_comparison_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_arg_comparison_report(args: SingleArgComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_arg_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_single_arg_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/single_operand_arithmetic/cli/workflow.rs b/packages/feature/lint-numeric/src/single_operand_arithmetic/cli/workflow.rs index 4b2ac49f8..e167e2a4f 100644 --- a/packages/feature/lint-numeric/src/single_operand_arithmetic/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/single_operand_arithmetic/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_operand_arithmetic::cli::args::SingleOperandArithmeticReportArgs; use crate::single_operand_arithmetic::cli::render::print_single_operand_arithmetic_report; use crate::single_operand_arithmetic::usecase::{ build_single_operand_arithmetic_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_operand_arithmetic_report(args: SingleOperandArithmeticReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_operand_arithmetic_report( + CliResult::Ok(build_single_operand_arithmetic_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/step_zero/cli/workflow.rs b/packages/feature/lint-numeric/src/step_zero/cli/workflow.rs index 2d5fea11b..f8488a7f8 100644 --- a/packages/feature/lint-numeric/src/step_zero/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/step_zero/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::step_zero::cli::args::StepZeroReportArgs; use crate::step_zero::cli::render::print_step_zero_report; use crate::step_zero::usecase::{build_step_zero_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn step_zero_report(args: StepZeroReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_step_zero_report(file, dialect, &tree)?); + CliResult::Ok(build_step_zero_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/t_comparison/cli/workflow.rs b/packages/feature/lint-numeric/src/t_comparison/cli/workflow.rs index 104f238bb..46e6110ef 100644 --- a/packages/feature/lint-numeric/src/t_comparison/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/t_comparison/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::t_comparison::cli::args::TComparisonReportArgs; use crate::t_comparison::cli::render::print_t_comparison_report; use crate::t_comparison::usecase::{build_t_comparison_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn t_comparison_report(args: TComparisonReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_t_comparison_report(file, dialect, &tree)?); + CliResult::Ok(build_t_comparison_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/verbose_negation/cli/workflow.rs b/packages/feature/lint-numeric/src/verbose_negation/cli/workflow.rs index f2d9a3f66..9533f66dd 100644 --- a/packages/feature/lint-numeric/src/verbose_negation/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/verbose_negation/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::verbose_negation::cli::args::VerboseNegationReportArgs; use crate::verbose_negation::cli::render::print_verbose_negation_report; use crate::verbose_negation::usecase::{ build_verbose_negation_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn verbose_negation_report(args: VerboseNegationReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_verbose_negation_report(file, dialect, &tree)?); + CliResult::Ok(build_verbose_negation_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-numeric/src/zero_divisor/cli/workflow.rs b/packages/feature/lint-numeric/src/zero_divisor/cli/workflow.rs index 85ba50082..37e295d86 100644 --- a/packages/feature/lint-numeric/src/zero_divisor/cli/workflow.rs +++ b/packages/feature/lint-numeric/src/zero_divisor/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::zero_divisor::cli::args::ZeroDivisorReportArgs; use crate::zero_divisor::cli::render::print_zero_divisor_report; use crate::zero_divisor::usecase::{build_zero_divisor_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn zero_divisor_report(args: ZeroDivisorReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_zero_divisor_report(file, dialect, &tree)?); + CliResult::Ok(build_zero_divisor_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/around_method_missing_call_next_method/cli/workflow.rs b/packages/feature/lint-object-system/src/around_method_missing_call_next_method/cli/workflow.rs index 96830c60f..2cda8adef 100644 --- a/packages/feature/lint-object-system/src/around_method_missing_call_next_method/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/around_method_missing_call_next_method/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::around_method_missing_call_next_method::cli::args::AroundMethodMissingCallNextMethodReportArgs; use crate::around_method_missing_call_next_method::cli::render::print_around_method_missing_call_next_method_report; use crate::around_method_missing_call_next_method::usecase::{ build_around_method_missing_call_next_method_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn around_method_missing_call_next_method_report( args: AroundMethodMissingCallNextMethodReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_around_method_missing_call_next_method_report( + CliResult::Ok(build_around_method_missing_call_next_method_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/defclass_required_slot_no_initform_or_initarg/cli/workflow.rs b/packages/feature/lint-object-system/src/defclass_required_slot_no_initform_or_initarg/cli/workflow.rs index 6827a9bd4..793383e83 100644 --- a/packages/feature/lint-object-system/src/defclass_required_slot_no_initform_or_initarg/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/defclass_required_slot_no_initform_or_initarg/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::defclass_required_slot_no_initform_or_initarg::cli::args::DefclassRequiredSlotNoInitformOrInitargReportArgs; use crate::defclass_required_slot_no_initform_or_initarg::cli::render::print_defclass_required_slot_no_initform_or_initarg_report; use crate::defclass_required_slot_no_initform_or_initarg::usecase::{ build_defclass_required_slot_no_initform_or_initarg_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn defclass_required_slot_no_initform_or_initarg_report( args: DefclassRequiredSlotNoInitformOrInitargReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_defclass_required_slot_no_initform_or_initarg_report( + CliResult::Ok(build_defclass_required_slot_no_initform_or_initarg_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/defclass_slot_shadowing/cli/workflow.rs b/packages/feature/lint-object-system/src/defclass_slot_shadowing/cli/workflow.rs index 9f28f74cb..d56e012ed 100644 --- a/packages/feature/lint-object-system/src/defclass_slot_shadowing/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/defclass_slot_shadowing/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::defclass_slot_shadowing::cli::args::DefclassSlotShadowingReportArgs; use crate::defclass_slot_shadowing::cli::render::print_defclass_slot_shadowing_report; use crate::defclass_slot_shadowing::usecase::{ build_defclass_slot_shadowing_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn defclass_slot_shadowing_report(args: DefclassSlotShadowingReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_defclass_slot_shadowing_report(file, dialect, &tree)?); + CliResult::Ok(build_defclass_slot_shadowing_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/duplicate_defmethod_signature/cli/workflow.rs b/packages/feature/lint-object-system/src/duplicate_defmethod_signature/cli/workflow.rs index a2a8f10a3..8ff9e4392 100644 --- a/packages/feature/lint-object-system/src/duplicate_defmethod_signature/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/duplicate_defmethod_signature/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_defmethod_signature::cli::args::DuplicateDefmethodSignatureReportArgs; use crate::duplicate_defmethod_signature::cli::render::print_duplicate_defmethod_signature_report; use crate::duplicate_defmethod_signature::usecase::{ build_duplicate_defmethod_signature_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_defmethod_signature_report( args: DuplicateDefmethodSignatureReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_defmethod_signature_report( + CliResult::Ok(build_duplicate_defmethod_signature_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/generic_function_no_methods/cli/workflow.rs b/packages/feature/lint-object-system/src/generic_function_no_methods/cli/workflow.rs index d28c60119..7ed73f6fc 100644 --- a/packages/feature/lint-object-system/src/generic_function_no_methods/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/generic_function_no_methods/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::generic_function_no_methods::cli::args::GenericFunctionNoMethodsReportArgs; use crate::generic_function_no_methods::cli::render::print_generic_function_no_methods_report; use crate::generic_function_no_methods::usecase::{ build_generic_function_no_methods_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn generic_function_no_methods_report( args: GenericFunctionNoMethodsReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_generic_function_no_methods_report( + CliResult::Ok(build_generic_function_no_methods_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/method_qualifier_typo/cli/workflow.rs b/packages/feature/lint-object-system/src/method_qualifier_typo/cli/workflow.rs index 32fc6bc2e..fae465c80 100644 --- a/packages/feature/lint-object-system/src/method_qualifier_typo/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/method_qualifier_typo/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::method_qualifier_typo::cli::args::MethodQualifierTypoReportArgs; use crate::method_qualifier_typo::cli::render::print_method_qualifier_typo_report; use crate::method_qualifier_typo::usecase::{ build_method_qualifier_typo_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn method_qualifier_typo_report(args: MethodQualifierTypoReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_method_qualifier_typo_report(file, dialect, &tree)?); + CliResult::Ok(build_method_qualifier_typo_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/print_object_without_print_unreadable_object/cli/workflow.rs b/packages/feature/lint-object-system/src/print_object_without_print_unreadable_object/cli/workflow.rs index 85de42146..4caf6f11b 100644 --- a/packages/feature/lint-object-system/src/print_object_without_print_unreadable_object/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/print_object_without_print_unreadable_object/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::print_object_without_print_unreadable_object::cli::args::PrintObjectWithoutPrintUnreadableObjectReportArgs; use crate::print_object_without_print_unreadable_object::cli::render::print_print_object_without_print_unreadable_object_report; use crate::print_object_without_print_unreadable_object::usecase::{ build_print_object_without_print_unreadable_object_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn print_object_without_print_unreadable_object_report( args: PrintObjectWithoutPrintUnreadableObjectReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_print_object_without_print_unreadable_object_report( + CliResult::Ok(build_print_object_without_print_unreadable_object_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-object-system/src/slot_value_bypasses_accessor/cli/workflow.rs b/packages/feature/lint-object-system/src/slot_value_bypasses_accessor/cli/workflow.rs index fbb5d3f52..99b02c109 100644 --- a/packages/feature/lint-object-system/src/slot_value_bypasses_accessor/cli/workflow.rs +++ b/packages/feature/lint-object-system/src/slot_value_bypasses_accessor/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::slot_value_bypasses_accessor::cli::args::SlotValueBypassesAccessorReportArgs; use crate::slot_value_bypasses_accessor::cli::render::print_slot_value_bypasses_accessor_report; use crate::slot_value_bypasses_accessor::usecase::{ build_slot_value_bypasses_accessor_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn slot_value_bypasses_accessor_report( args: SlotValueBypassesAccessorReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_slot_value_bypasses_accessor_report( + CliResult::Ok(build_slot_value_bypasses_accessor_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-package-hygiene/src/package_circular_in_package_chain/cli/workflow.rs b/packages/feature/lint-package-hygiene/src/package_circular_in_package_chain/cli/workflow.rs index 1cbc33de9..697620aed 100644 --- a/packages/feature/lint-package-hygiene/src/package_circular_in_package_chain/cli/workflow.rs +++ b/packages/feature/lint-package-hygiene/src/package_circular_in_package_chain/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::package_circular_in_package_chain::cli::args::CircularInPackageChainReportArgs; use crate::package_circular_in_package_chain::cli::render::print_circular_in_package_chain_report; use crate::package_circular_in_package_chain::usecase::{ build_circular_in_package_chain_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn circular_in_package_chain_report(args: CircularInPackageChainReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_circular_in_package_chain_report( + CliResult::Ok(build_circular_in_package_chain_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-repl-debug/src/commented_repl_transcript/cli/workflow.rs b/packages/feature/lint-repl-debug/src/commented_repl_transcript/cli/workflow.rs index 411306b03..6106a5dfd 100644 --- a/packages/feature/lint-repl-debug/src/commented_repl_transcript/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/commented_repl_transcript/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::commented_repl_transcript::cli::args::CommentedReplTranscriptReportArgs; use crate::commented_repl_transcript::cli::render::print_commented_repl_transcript_report; @@ -6,21 +6,25 @@ use crate::commented_repl_transcript::usecase::{ CommentedReplTranscriptPolicyOptions, collect_commented_repl_transcript, evaluate_commented_repl_transcript_policy, summarize_commented_repl_transcript, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn commented_repl_transcript_report(args: CommentedReplTranscriptReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_commented_repl_transcript(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_commented_repl_transcript(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_commented_repl_transcript(scanned_form_count, violations); let policy = evaluate_commented_repl_transcript_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_break_call/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_break_call/cli/workflow.rs index e2848c689..66e254cae 100644 --- a/packages/feature/lint-repl-debug/src/leftover_break_call/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_break_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_break_call::cli::args::LeftoverBreakCallReportArgs; use crate::leftover_break_call::cli::render::print_leftover_break_call_report; @@ -6,20 +6,25 @@ use crate::leftover_break_call::usecase::{ LeftoverBreakCallPolicyOptions, collect_leftover_break_call, evaluate_leftover_break_call_policy, summarize_leftover_break_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_break_call_report(args: LeftoverBreakCallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = collect_leftover_break_call(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_break_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_break_call(scanned_form_count, violations); let policy = evaluate_leftover_break_call_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/cli/workflow.rs index cb56a406e..871921574 100644 --- a/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_format_debug_marker::cli::args::LeftoverFormatDebugMarkerReportArgs; use crate::leftover_format_debug_marker::cli::render::print_leftover_format_debug_marker_report; @@ -6,23 +6,27 @@ use crate::leftover_format_debug_marker::usecase::{ LeftoverFormatDebugMarkerPolicyOptions, collect_leftover_format_debug_marker, evaluate_leftover_format_debug_marker_policy, summarize_leftover_format_debug_marker, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_format_debug_marker_report( args: LeftoverFormatDebugMarkerReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_leftover_format_debug_marker(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_format_debug_marker(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_format_debug_marker(scanned_form_count, violations); let policy = evaluate_leftover_format_debug_marker_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_inspect_call/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_inspect_call/cli/workflow.rs index ec4874037..969a07f19 100644 --- a/packages/feature/lint-repl-debug/src/leftover_inspect_call/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_inspect_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_inspect_call::cli::args::LeftoverInspectCallReportArgs; use crate::leftover_inspect_call::cli::render::print_leftover_inspect_call_report; @@ -6,21 +6,25 @@ use crate::leftover_inspect_call::usecase::{ LeftoverInspectCallPolicyOptions, collect_leftover_inspect_call, evaluate_leftover_inspect_call_policy, summarize_leftover_inspect_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_inspect_call_report(args: LeftoverInspectCallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_leftover_inspect_call(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_inspect_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_inspect_call(scanned_form_count, violations); let policy = evaluate_leftover_inspect_call_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_print_debug/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_print_debug/cli/workflow.rs index 9be3d6a4c..c5284f0e5 100644 --- a/packages/feature/lint-repl-debug/src/leftover_print_debug/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_print_debug/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_print_debug::cli::args::LeftoverPrintDebugReportArgs; use crate::leftover_print_debug::cli::render::print_leftover_print_debug_report; @@ -6,21 +6,25 @@ use crate::leftover_print_debug::usecase::{ LeftoverPrintDebugPolicyOptions, collect_leftover_print_debug, evaluate_leftover_print_debug_policy, summarize_leftover_print_debug, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_print_debug_report(args: LeftoverPrintDebugReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_leftover_print_debug(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_print_debug(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_print_debug(scanned_form_count, violations); let policy = evaluate_leftover_print_debug_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_step_call/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_step_call/cli/workflow.rs index aefe6ff29..994b11464 100644 --- a/packages/feature/lint-repl-debug/src/leftover_step_call/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_step_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_step_call::cli::args::LeftoverStepCallReportArgs; use crate::leftover_step_call::cli::render::print_leftover_step_call_report; @@ -6,20 +6,25 @@ use crate::leftover_step_call::usecase::{ LeftoverStepCallPolicyOptions, collect_leftover_step_call, evaluate_leftover_step_call_policy, summarize_leftover_step_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_step_call_report(args: LeftoverStepCallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = collect_leftover_step_call(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_step_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_step_call(scanned_form_count, violations); let policy = evaluate_leftover_step_call_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_time_benchmark_call/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_time_benchmark_call/cli/workflow.rs index 88531b0aa..d2c3c11d2 100644 --- a/packages/feature/lint-repl-debug/src/leftover_time_benchmark_call/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_time_benchmark_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_time_benchmark_call::cli::args::LeftoverTimeBenchmarkCallReportArgs; use crate::leftover_time_benchmark_call::cli::render::print_leftover_time_benchmark_call_report; @@ -6,23 +6,27 @@ use crate::leftover_time_benchmark_call::usecase::{ LeftoverTimeBenchmarkCallPolicyOptions, collect_leftover_time_benchmark_call, evaluate_leftover_time_benchmark_call_policy, summarize_leftover_time_benchmark_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_time_benchmark_call_report( args: LeftoverTimeBenchmarkCallReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = - collect_leftover_time_benchmark_call(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_time_benchmark_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_time_benchmark_call(scanned_form_count, violations); let policy = evaluate_leftover_time_benchmark_call_policy( diff --git a/packages/feature/lint-repl-debug/src/leftover_trace_call/cli/workflow.rs b/packages/feature/lint-repl-debug/src/leftover_trace_call/cli/workflow.rs index 3f5f8c5b9..8f287fb16 100644 --- a/packages/feature/lint-repl-debug/src/leftover_trace_call/cli/workflow.rs +++ b/packages/feature/lint-repl-debug/src/leftover_trace_call/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::leftover_trace_call::cli::args::LeftoverTraceCallReportArgs; use crate::leftover_trace_call::cli::render::print_leftover_trace_call_report; @@ -6,20 +6,25 @@ use crate::leftover_trace_call::usecase::{ LeftoverTraceCallPolicyOptions, collect_leftover_trace_call, evaluate_leftover_trace_call_policy, summarize_leftover_trace_call, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn leftover_trace_call_report(args: LeftoverTraceCallReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut scanned_form_count = 0; - let mut violations = Vec::new(); - - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_form_count, file_violations) = collect_leftover_trace_call(file, dialect, &tree)?; - scanned_form_count += file_form_count; - violations.extend(file_violations); + CliResult::Ok(collect_leftover_trace_call(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (form_counts, violation_lists): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let scanned_form_count: usize = form_counts.into_iter().sum(); + let violations: Vec<_> = violation_lists.into_iter().flatten().collect(); let summary = summarize_leftover_trace_call(scanned_form_count, violations); let policy = evaluate_leftover_trace_call_policy( diff --git a/packages/feature/lint-scheme-idiom/src/begin_single_form/cli/workflow.rs b/packages/feature/lint-scheme-idiom/src/begin_single_form/cli/workflow.rs index 33314bc99..021cac7ba 100644 --- a/packages/feature/lint-scheme-idiom/src/begin_single_form/cli/workflow.rs +++ b/packages/feature/lint-scheme-idiom/src/begin_single_form/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::begin_single_form::cli::args::BeginSingleFormReportArgs; use crate::begin_single_form::cli::render::print_begin_single_form_report; use crate::begin_single_form::usecase::{ build_begin_single_form_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn begin_single_form_report(args: BeginSingleFormReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_begin_single_form_report(file, dialect, &tree)?); + CliResult::Ok(build_begin_single_form_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-scheme-idiom/src/let_star_independent_bindings/cli/workflow.rs b/packages/feature/lint-scheme-idiom/src/let_star_independent_bindings/cli/workflow.rs index acaeadf01..0c58b91e4 100644 --- a/packages/feature/lint-scheme-idiom/src/let_star_independent_bindings/cli/workflow.rs +++ b/packages/feature/lint-scheme-idiom/src/let_star_independent_bindings/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::let_star_independent_bindings::cli::args::LetStarIndependentBindingsReportArgs; use crate::let_star_independent_bindings::cli::render::print_let_star_independent_bindings_report; use crate::let_star_independent_bindings::usecase::{ build_let_star_independent_bindings_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn let_star_independent_bindings_report( args: LetStarIndependentBindingsReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_let_star_independent_bindings_report( + CliResult::Ok(build_let_star_independent_bindings_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-scheme-idiom/src/memq_assq_literal_key/cli/workflow.rs b/packages/feature/lint-scheme-idiom/src/memq_assq_literal_key/cli/workflow.rs index d9b5dc3d9..ba365515d 100644 --- a/packages/feature/lint-scheme-idiom/src/memq_assq_literal_key/cli/workflow.rs +++ b/packages/feature/lint-scheme-idiom/src/memq_assq_literal_key/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::memq_assq_literal_key::cli::args::MemqAssqLiteralKeyReportArgs; use crate::memq_assq_literal_key::cli::render::print_memq_assq_literal_key_report; use crate::memq_assq_literal_key::usecase::{ build_memq_assq_literal_key_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn memq_assq_literal_key_report(args: MemqAssqLiteralKeyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_memq_assq_literal_key_report(file, dialect, &tree)?); + CliResult::Ok(build_memq_assq_literal_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-scheme-idiom/src/named_let_never_recurs/cli/workflow.rs b/packages/feature/lint-scheme-idiom/src/named_let_never_recurs/cli/workflow.rs index cf10d49e5..bfe6f246a 100644 --- a/packages/feature/lint-scheme-idiom/src/named_let_never_recurs/cli/workflow.rs +++ b/packages/feature/lint-scheme-idiom/src/named_let_never_recurs/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::named_let_never_recurs::cli::args::NamedLetNeverRecursReportArgs; use crate::named_let_never_recurs::cli::render::print_named_let_never_recurs_report; use crate::named_let_never_recurs::usecase::{ build_named_let_never_recurs_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn named_let_never_recurs_report(args: NamedLetNeverRecursReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_named_let_never_recurs_report(file, dialect, &tree)?); + CliResult::Ok(build_named_let_never_recurs_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/accessor_arity/cli/workflow.rs b/packages/feature/lint-sequence/src/accessor_arity/cli/workflow.rs index 822979ad1..59e00cd3b 100644 --- a/packages/feature/lint-sequence/src/accessor_arity/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/accessor_arity/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::accessor_arity::cli::args::AccessorArityReportArgs; use crate::accessor_arity::cli::render::print_accessor_arity_report; use crate::accessor_arity::usecase::{ collect_accessor_arity_violations, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn accessor_arity_report(args: AccessorArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_accessor_arity_violations(file, dialect, &tree)?); + CliResult::Ok(collect_accessor_arity_violations(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/append_list_to_cons/cli/workflow.rs b/packages/feature/lint-sequence/src/append_list_to_cons/cli/workflow.rs index 342eec64d..20ed3b497 100644 --- a/packages/feature/lint-sequence/src/append_list_to_cons/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/append_list_to_cons/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::append_list_to_cons::cli::args::AppendListToConsReportArgs; use crate::append_list_to_cons::cli::render::print_append_list_to_cons_report; use crate::append_list_to_cons::usecase::{ collect_append_list_to_cons, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn append_list_to_cons_report(args: AppendListToConsReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_append_list_to_cons(file, dialect, &tree)?); + CliResult::Ok(collect_append_list_to_cons(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/append_nil/cli/workflow.rs b/packages/feature/lint-sequence/src/append_nil/cli/workflow.rs index bf2790a2e..8a476c393 100644 --- a/packages/feature/lint-sequence/src/append_nil/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/append_nil/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::append_nil::cli::args::AppendNilReportArgs; use crate::append_nil::cli::render::print_append_nil_report; use crate::append_nil::usecase::{collect_append_nils, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn append_nil_report(args: AppendNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_append_nils(file, dialect, &tree)?); + CliResult::Ok(collect_append_nils(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/car_nthcdr/cli/workflow.rs b/packages/feature/lint-sequence/src/car_nthcdr/cli/workflow.rs index d8c254677..151396d2d 100644 --- a/packages/feature/lint-sequence/src/car_nthcdr/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/car_nthcdr/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::car_nthcdr::cli::args::CarNthcdrReportArgs; use crate::car_nthcdr::cli::render::print_car_nthcdr_report; use crate::car_nthcdr::usecase::{collect_car_nthcdrs, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn car_nthcdr_report(args: CarNthcdrReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_car_nthcdrs(file, dialect, &tree)?); + CliResult::Ok(collect_car_nthcdrs(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/car_reverse/cli/workflow.rs b/packages/feature/lint-sequence/src/car_reverse/cli/workflow.rs index 4b0e4b87a..e14990fe1 100644 --- a/packages/feature/lint-sequence/src/car_reverse/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/car_reverse/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::car_reverse::cli::args::CarReverseReportArgs; use crate::car_reverse::cli::render::print_car_reverse_report; use crate::car_reverse::usecase::{collect_car_reverses, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn car_reverse_report(args: CarReverseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_car_reverses(file, dialect, &tree)?); + CliResult::Ok(collect_car_reverses(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/cons_to_list/cli/workflow.rs b/packages/feature/lint-sequence/src/cons_to_list/cli/workflow.rs index 8b8ecfd20..c13686be2 100644 --- a/packages/feature/lint-sequence/src/cons_to_list/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/cons_to_list/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::cons_to_list::cli::args::ConsToListReportArgs; use crate::cons_to_list::cli::render::print_cons_to_list_report; use crate::cons_to_list::usecase::{collect_cons_to_lists, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn cons_to_list_report(args: ConsToListReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_cons_to_lists(file, dialect, &tree)?); + CliResult::Ok(collect_cons_to_lists(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/destructive_literal/cli/workflow.rs b/packages/feature/lint-sequence/src/destructive_literal/cli/workflow.rs index cece8b771..d6d11b1b5 100644 --- a/packages/feature/lint-sequence/src/destructive_literal/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/destructive_literal/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::destructive_literal::cli::args::DestructiveLiteralReportArgs; use crate::destructive_literal::cli::render::print_destructive_literal_report; use crate::destructive_literal::usecase::{ collect_destructive_literals, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn destructive_literal_report(args: DestructiveLiteralReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_destructive_literals(file, dialect, &tree)?); + CliResult::Ok(collect_destructive_literals(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/double_reverse/cli/workflow.rs b/packages/feature/lint-sequence/src/double_reverse/cli/workflow.rs index ef4a92a48..a4caa7de9 100644 --- a/packages/feature/lint-sequence/src/double_reverse/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/double_reverse/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::double_reverse::cli::args::DoubleReverseReportArgs; use crate::double_reverse::cli::render::print_double_reverse_report; use crate::double_reverse::usecase::{ build_double_reverse_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn double_reverse_report(args: DoubleReverseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_double_reverse_report(file, dialect, &tree)?); + CliResult::Ok(build_double_reverse_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/eql_search_literal/cli/workflow.rs b/packages/feature/lint-sequence/src/eql_search_literal/cli/workflow.rs index dcb225ac2..841ae93bf 100644 --- a/packages/feature/lint-sequence/src/eql_search_literal/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/eql_search_literal/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::eql_search_literal::cli::args::EqlSearchLiteralReportArgs; use crate::eql_search_literal::cli::render::print_eql_search_literal_report; use crate::eql_search_literal::usecase::{ build_eql_search_literal_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn eql_search_literal_report(args: EqlSearchLiteralReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_eql_search_literal_report(file, dialect, &tree)?); + CliResult::Ok(build_eql_search_literal_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/cli/workflow.rs b/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/cli/workflow.rs index dab1ac183..9e8f59e46 100644 --- a/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::hash_table_iteration_order_assumed::cli::args::HashTableIterationOrderAssumedReportArgs; use crate::hash_table_iteration_order_assumed::cli::render::print_hash_table_iteration_order_assumed_report; use crate::hash_table_iteration_order_assumed::usecase::{ collect_hash_order_assumptions, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn hash_table_iteration_order_assumed_report( args: HashTableIterationOrderAssumedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_hash_order_assumptions(file, dialect, &tree)?); + CliResult::Ok(collect_hash_order_assumptions(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/last_default_count/cli/workflow.rs b/packages/feature/lint-sequence/src/last_default_count/cli/workflow.rs index 3def8597a..47ef00f6a 100644 --- a/packages/feature/lint-sequence/src/last_default_count/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/last_default_count/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::last_default_count::cli::args::LastDefaultCountReportArgs; use crate::last_default_count::cli::render::print_last_default_count_report; use crate::last_default_count::usecase::{ build_last_default_count_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn last_default_count_report(args: LastDefaultCountReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_last_default_count_report(file, dialect, &tree)?); + CliResult::Ok(build_last_default_count_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/list_star_nil/cli/workflow.rs b/packages/feature/lint-sequence/src/list_star_nil/cli/workflow.rs index 4f5ecdbe3..f5cb62dea 100644 --- a/packages/feature/lint-sequence/src/list_star_nil/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/list_star_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::list_star_nil::cli::args::ListStarNilReportArgs; use crate::list_star_nil::cli::render::print_list_star_nil_report; use crate::list_star_nil::usecase::{ build_list_star_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn list_star_nil_report(args: ListStarNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_list_star_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_list_star_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/list_star_to_cons/cli/workflow.rs b/packages/feature/lint-sequence/src/list_star_to_cons/cli/workflow.rs index 3cb5f00bf..a1f3f6eea 100644 --- a/packages/feature/lint-sequence/src/list_star_to_cons/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/list_star_to_cons/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::list_star_to_cons::cli::args::ListStarToConsReportArgs; use crate::list_star_to_cons::cli::render::print_list_star_to_cons_report; use crate::list_star_to_cons::usecase::{ build_list_star_to_cons_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn list_star_to_cons_report(args: ListStarToConsReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_list_star_to_cons_report(file, dialect, &tree)?); + CliResult::Ok(build_list_star_to_cons_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/nested_get_chain/cli/workflow.rs b/packages/feature/lint-sequence/src/nested_get_chain/cli/workflow.rs index bd50a91bd..cd26030c4 100644 --- a/packages/feature/lint-sequence/src/nested_get_chain/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/nested_get_chain/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_get_chain::cli::args::NestedGetChainReportArgs; use crate::nested_get_chain::cli::render::print_nested_get_chain_report; use crate::nested_get_chain::usecase::{collect_get_chains, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_get_chain_report(args: NestedGetChainReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_get_chains(file, dialect, &tree)?); + CliResult::Ok(collect_get_chains(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/nth_constant_index/cli/workflow.rs b/packages/feature/lint-sequence/src/nth_constant_index/cli/workflow.rs index 6ebce66ac..c3951512e 100644 --- a/packages/feature/lint-sequence/src/nth_constant_index/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/nth_constant_index/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nth_constant_index::cli::args::NthConstantIndexReportArgs; use crate::nth_constant_index::cli::render::print_nth_constant_index_report; use crate::nth_constant_index::usecase::{ build_nth_constant_index_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nth_constant_index_report(args: NthConstantIndexReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nth_constant_index_report(file, dialect, &tree)?); + CliResult::Ok(build_nth_constant_index_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/nthcdr_small_index/cli/workflow.rs b/packages/feature/lint-sequence/src/nthcdr_small_index/cli/workflow.rs index 97eff0a31..4a6501ce7 100644 --- a/packages/feature/lint-sequence/src/nthcdr_small_index/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/nthcdr_small_index/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nthcdr_small_index::cli::args::NthcdrSmallIndexReportArgs; use crate::nthcdr_small_index::cli::render::print_nthcdr_small_index_report; use crate::nthcdr_small_index::usecase::{ build_nthcdr_small_index_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nthcdr_small_index_report(args: NthcdrSmallIndexReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nthcdr_small_index_report(file, dialect, &tree)?); + CliResult::Ok(build_nthcdr_small_index_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/nthcdr_zero/cli/workflow.rs b/packages/feature/lint-sequence/src/nthcdr_zero/cli/workflow.rs index 068de1264..ab72b5f4a 100644 --- a/packages/feature/lint-sequence/src/nthcdr_zero/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/nthcdr_zero/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nthcdr_zero::cli::args::NthcdrZeroReportArgs; use crate::nthcdr_zero::cli::render::print_nthcdr_zero_report; use crate::nthcdr_zero::usecase::{build_nthcdr_zero_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nthcdr_zero_report(args: NthcdrZeroReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nthcdr_zero_report(file, dialect, &tree)?); + CliResult::Ok(build_nthcdr_zero_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_count_nil/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_count_nil/cli/workflow.rs index fb8dc5de8..3bf2b2c45 100644 --- a/packages/feature/lint-sequence/src/redundant_count_nil/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_count_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_count_nil::cli::args::RedundantCountNilReportArgs; use crate::redundant_count_nil::cli::render::print_redundant_count_nil_report; use crate::redundant_count_nil::usecase::{ build_redundant_count_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_count_nil_report(args: RedundantCountNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_count_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_count_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_end_nil/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_end_nil/cli/workflow.rs index 08cd1d062..7449f9b56 100644 --- a/packages/feature/lint-sequence/src/redundant_end_nil/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_end_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_end_nil::cli::args::RedundantEndNilReportArgs; use crate::redundant_end_nil::cli::render::print_redundant_end_nil_report; use crate::redundant_end_nil::usecase::{ build_redundant_end_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_end_nil_report(args: RedundantEndNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_end_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_end_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_eql_test/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_eql_test/cli/workflow.rs index 5fb53bdea..679d548a2 100644 --- a/packages/feature/lint-sequence/src/redundant_eql_test/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_eql_test/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_eql_test::cli::args::RedundantEqlTestReportArgs; use crate::redundant_eql_test::cli::render::print_redundant_eql_test_report; use crate::redundant_eql_test::usecase::{ build_redundant_eql_test_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_eql_test_report(args: RedundantEqlTestReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_eql_test_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_eql_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_from_end_nil/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_from_end_nil/cli/workflow.rs index 68b454729..b1de49bfd 100644 --- a/packages/feature/lint-sequence/src/redundant_from_end_nil/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_from_end_nil/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_from_end_nil::cli::args::RedundantFromEndNilReportArgs; use crate::redundant_from_end_nil::cli::render::print_redundant_from_end_nil_report; use crate::redundant_from_end_nil::usecase::{ build_redundant_from_end_nil_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_from_end_nil_report(args: RedundantFromEndNilReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_from_end_nil_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_from_end_nil_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_identity_key/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_identity_key/cli/workflow.rs index 6d2d6e82f..9273189fe 100644 --- a/packages/feature/lint-sequence/src/redundant_identity_key/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_identity_key/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_identity_key::cli::args::RedundantIdentityKeyReportArgs; use crate::redundant_identity_key::cli::render::print_redundant_identity_key_report; use crate::redundant_identity_key::usecase::{ build_redundant_identity_key_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_identity_key_report(args: RedundantIdentityKeyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_identity_key_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_identity_key_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_into_empty_collection/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_into_empty_collection/cli/workflow.rs index 4f2859ba1..bc883d0bb 100644 --- a/packages/feature/lint-sequence/src/redundant_into_empty_collection/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_into_empty_collection/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_into_empty_collection::cli::args::RedundantIntoEmptyCollectionReportArgs; use crate::redundant_into_empty_collection::cli::render::print_redundant_into_empty_collection_report; use crate::redundant_into_empty_collection::usecase::{ collect_redundant_intos, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_into_empty_collection_report( args: RedundantIntoEmptyCollectionReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_redundant_intos(file, dialect, &tree)?); + CliResult::Ok(collect_redundant_intos(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/redundant_start_zero/cli/workflow.rs b/packages/feature/lint-sequence/src/redundant_start_zero/cli/workflow.rs index 9ebb64361..b5261170f 100644 --- a/packages/feature/lint-sequence/src/redundant_start_zero/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/redundant_start_zero/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::redundant_start_zero::cli::args::RedundantStartZeroReportArgs; use crate::redundant_start_zero::cli::render::print_redundant_start_zero_report; use crate::redundant_start_zero::usecase::{ build_redundant_start_zero_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn redundant_start_zero_report(args: RedundantStartZeroReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_redundant_start_zero_report(file, dialect, &tree)?); + CliResult::Ok(build_redundant_start_zero_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/set_membership_via_linear_scan/cli/workflow.rs b/packages/feature/lint-sequence/src/set_membership_via_linear_scan/cli/workflow.rs index 461dd0da0..9c558c54d 100644 --- a/packages/feature/lint-sequence/src/set_membership_via_linear_scan/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/set_membership_via_linear_scan/cli/workflow.rs @@ -1,22 +1,29 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::set_membership_via_linear_scan::cli::args::SetMembershipViaLinearScanReportArgs; use crate::set_membership_via_linear_scan::cli::render::print_set_membership_via_linear_scan_report; use crate::set_membership_via_linear_scan::usecase::{ collect_linear_scans, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn set_membership_via_linear_scan_report( args: SetMembershipViaLinearScanReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(collect_linear_scans(file, dialect, &tree)?); + CliResult::Ok(collect_linear_scans(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/single_operand_list_op/cli/workflow.rs b/packages/feature/lint-sequence/src/single_operand_list_op/cli/workflow.rs index 997197c92..a2986cbb9 100644 --- a/packages/feature/lint-sequence/src/single_operand_list_op/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/single_operand_list_op/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::single_operand_list_op::cli::args::SingleOperandListOpReportArgs; use crate::single_operand_list_op::cli::render::print_single_operand_list_op_report; use crate::single_operand_list_op::usecase::{ build_single_operand_list_op_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn single_operand_list_op_report(args: SingleOperandListOpReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_single_operand_list_op_report(file, dialect, &tree)?); + CliResult::Ok(build_single_operand_list_op_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-sequence/src/subseq_zero/cli/workflow.rs b/packages/feature/lint-sequence/src/subseq_zero/cli/workflow.rs index ae9a9b0e3..f2c041205 100644 --- a/packages/feature/lint-sequence/src/subseq_zero/cli/workflow.rs +++ b/packages/feature/lint-sequence/src/subseq_zero/cli/workflow.rs @@ -1,18 +1,25 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::subseq_zero::cli::args::SubseqZeroReportArgs; use crate::subseq_zero::cli::render::print_subseq_zero_report; use crate::subseq_zero::usecase::{build_subseq_zero_report, evaluate_fail_on_violation_policy}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn subseq_zero_report(args: SubseqZeroReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_subseq_zero_report(file, dialect, &tree)?); + CliResult::Ok(build_subseq_zero_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/char_case_fold/cli/workflow.rs b/packages/feature/lint-string-char/src/char_case_fold/cli/workflow.rs index 4cc317c7d..7e1d9af1c 100644 --- a/packages/feature/lint-string-char/src/char_case_fold/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/char_case_fold/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::char_case_fold::cli::args::CharCaseFoldReportArgs; use crate::char_case_fold::cli::render::print_char_case_fold_report; use crate::char_case_fold::usecase::{ build_char_case_fold_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn char_case_fold_report(args: CharCaseFoldReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_char_case_fold_report(file, dialect, &tree)?); + CliResult::Ok(build_char_case_fold_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/char_op_string/cli/workflow.rs b/packages/feature/lint-string-char/src/char_op_string/cli/workflow.rs index 09c682c54..397bd99ec 100644 --- a/packages/feature/lint-string-char/src/char_op_string/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/char_op_string/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::char_op_string::cli::args::CharOpStringReportArgs; use crate::char_op_string::cli::render::print_char_op_string_report; use crate::char_op_string::usecase::{ build_char_op_string_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn char_op_string_report(args: CharOpStringReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_char_op_string_report(file, dialect, &tree)?); + CliResult::Ok(build_char_op_string_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/code_char_char_code/cli/workflow.rs b/packages/feature/lint-string-char/src/code_char_char_code/cli/workflow.rs index d06227a62..42fd54b20 100644 --- a/packages/feature/lint-string-char/src/code_char_char_code/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/code_char_char_code/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::code_char_char_code::cli::args::CodeCharCharCodeReportArgs; use crate::code_char_char_code::cli::render::print_code_char_char_code_report; use crate::code_char_char_code::usecase::{ build_code_char_char_code_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn code_char_char_code_report(args: CodeCharCharCodeReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_code_char_char_code_report(file, dialect, &tree)?); + CliResult::Ok(build_code_char_char_code_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_missing_destination/cli/workflow.rs b/packages/feature/lint-string-char/src/format_missing_destination/cli/workflow.rs index 29de17192..d2f0fcf63 100644 --- a/packages/feature/lint-string-char/src/format_missing_destination/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_missing_destination/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_missing_destination::cli::args::FormatMissingDestinationReportArgs; use crate::format_missing_destination::cli::render::print_format_missing_destination_report; use crate::format_missing_destination::usecase::{ build_format_missing_destination_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_missing_destination_report( args: FormatMissingDestinationReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_missing_destination_report( + CliResult::Ok(build_format_missing_destination_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_nested_directive_unbalanced/cli/workflow.rs b/packages/feature/lint-string-char/src/format_nested_directive_unbalanced/cli/workflow.rs index 1c9725975..e00bfdff8 100644 --- a/packages/feature/lint-string-char/src/format_nested_directive_unbalanced/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_nested_directive_unbalanced/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_nested_directive_unbalanced::cli::args::FormatNestedDirectiveUnbalancedReportArgs; use crate::format_nested_directive_unbalanced::cli::render::print_format_nested_directive_unbalanced_report; use crate::format_nested_directive_unbalanced::usecase::{ build_format_nested_directive_unbalanced_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_nested_directive_unbalanced_report( args: FormatNestedDirectiveUnbalancedReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_nested_directive_unbalanced_report( + CliResult::Ok(build_format_nested_directive_unbalanced_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_newline/cli/workflow.rs b/packages/feature/lint-string-char/src/format_newline/cli/workflow.rs index 9b65826a9..31ca0fb88 100644 --- a/packages/feature/lint-string-char/src/format_newline/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_newline/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_newline::cli::args::FormatNewlineReportArgs; use crate::format_newline::cli::render::print_format_newline_report; use crate::format_newline::usecase::{ build_format_newline_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_newline_report(args: FormatNewlineReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_newline_report(file, dialect, &tree)?); + CliResult::Ok(build_format_newline_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_percent_ampersand_adjacent_redundancy/cli/workflow.rs b/packages/feature/lint-string-char/src/format_percent_ampersand_adjacent_redundancy/cli/workflow.rs index 53c4e5421..460333dfa 100644 --- a/packages/feature/lint-string-char/src/format_percent_ampersand_adjacent_redundancy/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_percent_ampersand_adjacent_redundancy/cli/workflow.rs @@ -1,24 +1,31 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_percent_ampersand_adjacent_redundancy::cli::args::FormatPercentAmpersandAdjacentRedundancyReportArgs; use crate::format_percent_ampersand_adjacent_redundancy::cli::render::print_format_percent_ampersand_adjacent_redundancy_report; use crate::format_percent_ampersand_adjacent_redundancy::usecase::{ build_format_percent_ampersand_adjacent_redundancy_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_percent_ampersand_adjacent_redundancy_report( args: FormatPercentAmpersandAdjacentRedundancyReportArgs, ) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_percent_ampersand_adjacent_redundancy_report( + CliResult::Ok(build_format_percent_ampersand_adjacent_redundancy_report( file, dialect, &tree, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_to_string/cli/workflow.rs b/packages/feature/lint-string-char/src/format_to_string/cli/workflow.rs index 6d908e46e..842002bc4 100644 --- a/packages/feature/lint-string-char/src/format_to_string/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_to_string/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_to_string::cli::args::FormatToStringReportArgs; use crate::format_to_string::cli::render::print_format_to_string_report; use crate::format_to_string::usecase::{ build_format_to_string_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_to_string_report(args: FormatToStringReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_to_string_report(file, dialect, &tree)?); + CliResult::Ok(build_format_to_string_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/format_unknown_directive/cli/workflow.rs b/packages/feature/lint-string-char/src/format_unknown_directive/cli/workflow.rs index 3e16dc0b7..e2a549e7d 100644 --- a/packages/feature/lint-string-char/src/format_unknown_directive/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/format_unknown_directive/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::format_unknown_directive::cli::args::FormatUnknownDirectiveReportArgs; use crate::format_unknown_directive::cli::render::print_format_unknown_directive_report; use crate::format_unknown_directive::usecase::{ build_format_unknown_directive_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn format_unknown_directive_report(args: FormatUnknownDirectiveReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_unknown_directive_report(file, dialect, &tree)?); + CliResult::Ok(build_format_unknown_directive_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/nested_string_case/cli/workflow.rs b/packages/feature/lint-string-char/src/nested_string_case/cli/workflow.rs index 6188f387e..65705a809 100644 --- a/packages/feature/lint-string-char/src/nested_string_case/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/nested_string_case/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::nested_string_case::cli::args::NestedStringCaseReportArgs; use crate::nested_string_case::cli::render::print_nested_string_case_report; use crate::nested_string_case::usecase::{ build_nested_string_case_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn nested_string_case_report(args: NestedStringCaseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_nested_string_case_report(file, dialect, &tree)?); + CliResult::Ok(build_nested_string_case_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-string-char/src/string_case_fold/cli/workflow.rs b/packages/feature/lint-string-char/src/string_case_fold/cli/workflow.rs index eb6b37192..183119f15 100644 --- a/packages/feature/lint-string-char/src/string_case_fold/cli/workflow.rs +++ b/packages/feature/lint-string-char/src/string_case_fold/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::string_case_fold::cli::args::StringCaseFoldReportArgs; use crate::string_case_fold::cli::render::print_string_case_fold_report; use crate::string_case_fold::usecase::{ build_string_case_fold_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn string_case_fold_report(args: StringCaseFoldReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_string_case_fold_report(file, dialect, &tree)?); + CliResult::Ok(build_string_case_fold_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/disabled_test_left_in/cli/workflow.rs b/packages/feature/lint-testing/src/disabled_test_left_in/cli/workflow.rs index 621b57543..4a73ec60a 100644 --- a/packages/feature/lint-testing/src/disabled_test_left_in/cli/workflow.rs +++ b/packages/feature/lint-testing/src/disabled_test_left_in/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::disabled_test_left_in::cli::args::DisabledTestLeftInReportArgs; use crate::disabled_test_left_in::cli::render::print_disabled_test_left_in_report; use crate::disabled_test_left_in::usecase::{ build_disabled_test_left_in_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn disabled_test_left_in_report(args: DisabledTestLeftInReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_disabled_test_left_in_report(file, dialect, &tree)?); + CliResult::Ok(build_disabled_test_left_in_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/duplicate_test_name/cli/workflow.rs b/packages/feature/lint-testing/src/duplicate_test_name/cli/workflow.rs index e00738088..cd416f13c 100644 --- a/packages/feature/lint-testing/src/duplicate_test_name/cli/workflow.rs +++ b/packages/feature/lint-testing/src/duplicate_test_name/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::duplicate_test_name::cli::args::DuplicateTestNameReportArgs; use crate::duplicate_test_name::cli::render::print_duplicate_test_name_report; use crate::duplicate_test_name::usecase::{ build_duplicate_test_name_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn duplicate_test_name_report(args: DuplicateTestNameReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_duplicate_test_name_report(file, dialect, &tree)?); + CliResult::Ok(build_duplicate_test_name_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/empty_test_body/cli/workflow.rs b/packages/feature/lint-testing/src/empty_test_body/cli/workflow.rs index df193c072..1c7d2abbe 100644 --- a/packages/feature/lint-testing/src/empty_test_body/cli/workflow.rs +++ b/packages/feature/lint-testing/src/empty_test_body/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::empty_test_body::cli::args::EmptyTestBodyReportArgs; use crate::empty_test_body::cli::render::print_empty_test_body_report; use crate::empty_test_body::usecase::{ build_empty_test_body_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn empty_test_body_report(args: EmptyTestBodyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_empty_test_body_report(file, dialect, &tree)?); + CliResult::Ok(build_empty_test_body_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/sleep_in_test/cli/workflow.rs b/packages/feature/lint-testing/src/sleep_in_test/cli/workflow.rs index a54eb479f..d48a9d20d 100644 --- a/packages/feature/lint-testing/src/sleep_in_test/cli/workflow.rs +++ b/packages/feature/lint-testing/src/sleep_in_test/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::sleep_in_test::cli::args::SleepInTestReportArgs; use crate::sleep_in_test::cli::render::print_sleep_in_test_report; use crate::sleep_in_test::usecase::{ build_sleep_in_test_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn sleep_in_test_report(args: SleepInTestReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_sleep_in_test_report(file, dialect, &tree)?); + CliResult::Ok(build_sleep_in_test_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/test_asserts_constant/cli/workflow.rs b/packages/feature/lint-testing/src/test_asserts_constant/cli/workflow.rs index ffa9f301e..c74edfbde 100644 --- a/packages/feature/lint-testing/src/test_asserts_constant/cli/workflow.rs +++ b/packages/feature/lint-testing/src/test_asserts_constant/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::test_asserts_constant::cli::args::TestAssertsConstantReportArgs; use crate::test_asserts_constant::cli::render::print_test_asserts_constant_report; use crate::test_asserts_constant::usecase::{ build_test_asserts_constant_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn test_asserts_constant_report(args: TestAssertsConstantReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_test_asserts_constant_report(file, dialect, &tree)?); + CliResult::Ok(build_test_asserts_constant_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lint-testing/src/test_without_assertion/cli/workflow.rs b/packages/feature/lint-testing/src/test_without_assertion/cli/workflow.rs index 2fc9d7616..01539a05a 100644 --- a/packages/feature/lint-testing/src/test_without_assertion/cli/workflow.rs +++ b/packages/feature/lint-testing/src/test_without_assertion/cli/workflow.rs @@ -1,20 +1,27 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::test_without_assertion::cli::args::TestWithoutAssertionReportArgs; use crate::test_without_assertion::cli::render::print_test_without_assertion_report; use crate::test_without_assertion::usecase::{ build_test_without_assertion_report, evaluate_fail_on_violation_policy, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files_raw, expand_input_files, note_partial_file_failures, read_input_dialect_and_tree, + total_file_failure, +}; pub fn test_without_assertion_report(args: TestWithoutAssertionReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { + let analysis = analyze_files_raw(&files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_test_without_assertion_report(file, dialect, &tree)?); + CliResult::Ok(build_test_without_assertion_report(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_violation_policy(args.fail_on_violation, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/circular_literal_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/circular_literal_report/cli/workflow.rs index 834693eef..499241bbf 100644 --- a/packages/feature/lisp-analysis/src/circular_literal_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/circular_literal_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::circular_literal_report::cli::args::CircularLiteralReportArgs; use crate::circular_literal_report::cli::render::print_label_report; @@ -11,11 +13,14 @@ use crate::circular_literal_report::usecase::{ pub fn circular_literal_report(args: CircularLiteralReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_circular_literal_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_circular_literal_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_label_policy(args.fail_on_label, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/class_hierarchy_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/class_hierarchy_report/cli/workflow.rs index eaca22c53..baca40f9b 100644 --- a/packages/feature/lisp-analysis/src/class_hierarchy_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/class_hierarchy_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::class_hierarchy_report::cli::args::ClassHierarchyReportArgs; use crate::class_hierarchy_report::cli::render::{ @@ -14,11 +16,14 @@ use paredit_core_cli::report::graph::print_graph; pub fn class_hierarchy_report(args: ClassHierarchyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_class_hierarchy_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_class_hierarchy_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_shadowed_slot_policy(args.fail_on_shadowed_slot, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/duplicate_method_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/duplicate_method_report/cli/workflow.rs index 063097914..3b4689803 100644 --- a/packages/feature/lisp-analysis/src/duplicate_method_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/duplicate_method_report/cli/workflow.rs @@ -6,15 +6,17 @@ use crate::duplicate_method_report::usecase::{ DuplicateMethodPolicyOptions, analyze_duplicate_methods, collect_declared_methods, evaluate_duplicate_method_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn duplicate_method_report(args: DuplicateMethodReportArgs) -> CommandResult { - let mut declared = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_methods(file, dialect, &tree)?); + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _input| { + collect_declared_methods(file, dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let declared: Vec<_> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_duplicate_methods(&declared); let policy = evaluate_duplicate_method_policy( diff --git a/packages/feature/lisp-analysis/src/duplicate_slot_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/duplicate_slot_report/cli/workflow.rs index 96aebb33b..1bc49e3dc 100644 --- a/packages/feature/lisp-analysis/src/duplicate_slot_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/duplicate_slot_report/cli/workflow.rs @@ -6,16 +6,20 @@ use crate::duplicate_slot_report::usecase::{ DuplicateSlotPolicyOptions, collect_duplicate_slots, evaluate_duplicate_slot_policy, summarize_duplicate_slots, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn duplicate_slot_report(args: DuplicateSlotReportArgs) -> CommandResult { + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _input| { + collect_duplicate_slots(file, dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + let mut definition_count = 0; let mut duplicates = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_definition_count, file_duplicates) = - collect_duplicate_slots(file, dialect, &tree)?; + for (file_definition_count, file_duplicates) in analysis.succeeded { definition_count += file_definition_count; duplicates.extend(file_duplicates); } diff --git a/packages/feature/lisp-analysis/src/format_directive_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/format_directive_report/cli/workflow.rs index 2a7ae752f..89e2bf0d1 100644 --- a/packages/feature/lisp-analysis/src/format_directive_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/format_directive_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::format_directive_report::cli::args::FormatDirectiveReportArgs; use crate::format_directive_report::cli::render::print_mismatch_report; @@ -11,11 +13,14 @@ use crate::format_directive_report::usecase::{ pub fn format_directive_report(args: FormatDirectiveReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_format_directive_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_format_directive_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_mismatch_policy(args.fail_on_mismatch, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/generic_dispatch_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/generic_dispatch_report/cli/workflow.rs index 055a2b48f..94fdf408c 100644 --- a/packages/feature/lisp-analysis/src/generic_dispatch_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/generic_dispatch_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::generic_dispatch_report::cli::args::GenericDispatchReportArgs; use crate::generic_dispatch_report::cli::render::print_defect_report; @@ -11,11 +13,14 @@ use crate::generic_dispatch_report::usecase::{ pub fn generic_dispatch_report(args: GenericDispatchReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_generic_dispatch_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_generic_dispatch_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_defect_policy(args.fail_on_defect, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/loop_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/loop_report/cli/workflow.rs index 603cd7a3d..fdfc07046 100644 --- a/packages/feature/lisp-analysis/src/loop_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/loop_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::loop_report::cli::args::LoopReportArgs; use crate::loop_report::cli::render::print_unterminated_report; @@ -9,11 +11,14 @@ use crate::loop_report::usecase::{build_loop_report, evaluate_fail_on_unterminat pub fn loop_report(args: LoopReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_loop_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_loop_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_unterminated_policy(args.fail_on_unterminated, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/macro_expansion_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/macro_expansion_report/cli/workflow.rs index ee0bb11a6..4ebef6832 100644 --- a/packages/feature/lisp-analysis/src/macro_expansion_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/macro_expansion_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::macro_expansion_report::cli::args::MacroExpansionReportArgs; use crate::macro_expansion_report::cli::render::print_declined_report; @@ -11,11 +13,14 @@ use crate::macro_expansion_report::usecase::{ pub fn macro_expansion_report(args: MacroExpansionReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_macro_expansion_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_macro_expansion_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_declined_policy(args.fail_on_declined, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/macro_hygiene_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/macro_hygiene_report/cli/workflow.rs index b4d09e458..a548fb108 100644 --- a/packages/feature/lisp-analysis/src/macro_hygiene_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/macro_hygiene_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::macro_hygiene_report::cli::args::MacroHygieneReportArgs; use crate::macro_hygiene_report::cli::render::print_risk_report; @@ -11,11 +13,14 @@ use crate::macro_hygiene_report::usecase::{ pub fn macro_hygiene_report(args: MacroHygieneReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_macro_hygiene_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_macro_hygiene_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_risk_policy(args.fail_on_risk, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/method_combination_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/method_combination_report/cli/workflow.rs index 15bd6c195..193ea543f 100644 --- a/packages/feature/lisp-analysis/src/method_combination_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/method_combination_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::method_combination_report::cli::args::MethodCombinationReportArgs; use crate::method_combination_report::cli::render::print_orphaned_report; @@ -11,11 +13,14 @@ use crate::method_combination_report::usecase::{ pub fn method_combination_report(args: MethodCombinationReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_method_combination_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_method_combination_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_orphaned_policy(args.fail_on_orphaned, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/package_lock_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/package_lock_report/cli/workflow.rs index 1e3fa4c91..42d8b21b8 100644 --- a/packages/feature/lisp-analysis/src/package_lock_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/package_lock_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::package_lock_report::cli::args::PackageLockReportArgs; use crate::package_lock_report::cli::render::print_undefined_behavior_report; @@ -11,11 +13,14 @@ use crate::package_lock_report::usecase::{ pub fn package_lock_report(args: PackageLockReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_package_lock_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_package_lock_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_undefined_behavior_policy(args.fail_on_undefined_behavior, &reports); diff --git a/packages/feature/lisp-analysis/src/read_conditional_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/read_conditional_report/cli/workflow.rs index bfe36e2b3..b06234574 100644 --- a/packages/feature/lisp-analysis/src/read_conditional_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/read_conditional_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::read_conditional_report::cli::args::ReadConditionalReportArgs; use crate::read_conditional_report::cli::render::print_conditional_report; @@ -11,11 +13,14 @@ use crate::read_conditional_report::usecase::{ pub fn read_conditional_report(args: ReadConditionalReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_read_conditional_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_read_conditional_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_conditional_policy(args.fail_on_conditional, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/read_time_eval_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/read_time_eval_report/cli/workflow.rs index da6141828..1f7eabfd7 100644 --- a/packages/feature/lisp-analysis/src/read_time_eval_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/read_time_eval_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::read_time_eval_report::cli::args::ReadTimeEvalReportArgs; use crate::read_time_eval_report::cli::render::print_read_eval_report; @@ -11,11 +13,14 @@ use crate::read_time_eval_report::usecase::{ pub fn read_time_eval_report(args: ReadTimeEvalReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_read_time_eval_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_read_time_eval_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_read_eval_policy(args.fail_on_read_eval, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/readtable_case_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/readtable_case_report/cli/workflow.rs index 6f3503c85..608e11bb0 100644 --- a/packages/feature/lisp-analysis/src/readtable_case_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/readtable_case_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::readtable_case_report::cli::args::ReadtableCaseReportArgs; use crate::readtable_case_report::cli::render::print_fragile_report; @@ -11,11 +13,14 @@ use crate::readtable_case_report::usecase::{ pub fn readtable_case_report(args: ReadtableCaseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_readtable_case_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_readtable_case_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_fragile_policy(args.fail_on_fragile, &reports); let passed = policy.passed; diff --git a/packages/feature/lisp-analysis/src/restart_report/cli/workflow.rs b/packages/feature/lisp-analysis/src/restart_report/cli/workflow.rs index 6cd0b7fe6..51b5d495b 100644 --- a/packages/feature/lisp-analysis/src/restart_report/cli/workflow.rs +++ b/packages/feature/lisp-analysis/src/restart_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::restart_report::cli::args::RestartReportArgs; use crate::restart_report::cli::render::print_unpaired_report; @@ -9,11 +11,14 @@ use crate::restart_report::usecase::{build_restart_report, evaluate_fail_on_unpa pub fn restart_report(args: RestartReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_restart_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_restart_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_unpaired_policy(args.fail_on_unpaired, &reports); let passed = policy.passed; diff --git a/packages/feature/package/src/duplicate_export_report/cli/workflow.rs b/packages/feature/package/src/duplicate_export_report/cli/workflow.rs index 600cbbba1..fe1b5e6ff 100644 --- a/packages/feature/package/src/duplicate_export_report/cli/workflow.rs +++ b/packages/feature/package/src/duplicate_export_report/cli/workflow.rs @@ -6,21 +6,24 @@ use crate::duplicate_export_report::usecase::{ DuplicateExportPolicyOptions, collect_duplicate_exports, evaluate_duplicate_export_policy, summarize_duplicate_exports, }; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; pub fn duplicate_export_report(args: DuplicateExportReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut defpackage_count = 0; - let mut duplicates = Vec::new(); - - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (file_defpackage_count, file_duplicates) = - collect_duplicate_exports(file, dialect, &tree)?; - defpackage_count += file_defpackage_count; - duplicates.extend(file_duplicates); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { + collect_duplicate_exports(file, dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (defpackage_counts, duplicate_lists): (Vec<_>, Vec<_>) = + analysis.succeeded.into_iter().unzip(); + let defpackage_count: usize = defpackage_counts.into_iter().sum(); + let duplicates: Vec<_> = duplicate_lists.into_iter().flatten().collect(); let summary = summarize_duplicate_exports(defpackage_count, duplicates); let policy = evaluate_duplicate_export_policy( diff --git a/packages/feature/package/src/package/cli/report.rs b/packages/feature/package/src/package/cli/report.rs index 9f5a6064a..15575ef83 100644 --- a/packages/feature/package/src/package/cli/report.rs +++ b/packages/feature/package/src/package/cli/report.rs @@ -1,7 +1,7 @@ use paredit_core_cli::CliResult; use crate::error::PackageCommandError; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use crate::package_report::usecase::build_package_report; @@ -11,23 +11,23 @@ use super::{ }; pub fn package_report(args: PackageReportArgs) -> CliResult<()> { - let mut reports = Vec::with_capacity(args.files.len()); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let report = build_package_report(&tree, dialect).map_err(|source| { - PackageCommandError::Inspect { + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + let report = + build_package_report(tree, dialect).map_err(|source| PackageCommandError::Inspect { path: file.display().to_string(), source, - } - })?; + })?; - reports.push(PackageReportFile { + CliResult::Ok(PackageReportFile { path: file.clone(), dialect, report, - }); + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); - print_package_report(&reports, args.output) + print_package_report(&analysis.succeeded, args.output) } diff --git a/packages/feature/package/src/package_boundary_report/cli/workflow.rs b/packages/feature/package/src/package_boundary_report/cli/workflow.rs index e5649cf89..5af53d797 100644 --- a/packages/feature/package/src/package_boundary_report/cli/workflow.rs +++ b/packages/feature/package/src/package_boundary_report/cli/workflow.rs @@ -3,19 +3,21 @@ use super::render::print_package_boundary_report; use crate::package_boundary_report::usecase::{ PackageBoundaryPolicyOptions, build_package_boundary_report, evaluate_package_boundary_policy, }; +use paredit_core_cli::CliResult; use paredit_core_cli::CommandResult; use paredit_core_cli::shared::expand_input_files; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn package_boundary_report(args: PackageBoundaryReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - - for file in &files { - let (_input, dialect, tree) = - read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_package_boundary_report(file.clone(), dialect, &tree)?); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_package_boundary_report(file.clone(), dialect, tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_package_boundary_policy( PackageBoundaryPolicyOptions::new(args.fail_on_violation), diff --git a/packages/feature/package/src/package_conflict_report/cli/workflow.rs b/packages/feature/package/src/package_conflict_report/cli/workflow.rs index db334ff91..87bc9e981 100644 --- a/packages/feature/package/src/package_conflict_report/cli/workflow.rs +++ b/packages/feature/package/src/package_conflict_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::package_conflict_report::cli::args::PackageConflictReportArgs; use crate::package_conflict_report::cli::render::print_package_conflict_report; @@ -6,15 +6,20 @@ use crate::package_conflict_report::usecase::{ PackageConflictPolicyOptions, analyze_package_conflicts, collect_declared_package_identifiers, evaluate_package_conflict_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn package_conflict_report(args: PackageConflictReportArgs) -> CommandResult { - let mut declared = Vec::new(); - - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_package_identifiers(file, dialect, &tree)?); + CliResult::Ok(collect_declared_package_identifiers(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let declared: Vec<_> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_package_conflicts(&declared); let policy = evaluate_package_conflict_policy( diff --git a/packages/feature/package/src/system_conflict_report/cli/workflow.rs b/packages/feature/package/src/system_conflict_report/cli/workflow.rs index 34c509351..1816668af 100644 --- a/packages/feature/package/src/system_conflict_report/cli/workflow.rs +++ b/packages/feature/package/src/system_conflict_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::system_conflict_report::cli::args::SystemConflictReportArgs; use crate::system_conflict_report::cli::render::print_system_conflict_report; @@ -6,15 +6,20 @@ use crate::system_conflict_report::usecase::{ SystemConflictPolicyOptions, analyze_system_conflicts, collect_declared_systems, evaluate_system_conflict_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn system_conflict_report(args: SystemConflictReportArgs) -> CommandResult { - let mut declared = Vec::new(); - - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_systems(file, dialect, &tree)?); + CliResult::Ok(collect_declared_systems(file, dialect, &tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let declared: Vec<_> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_system_conflicts(&declared); let policy = evaluate_system_conflict_policy( diff --git a/packages/feature/package/src/unused_export_report/cli/workflow.rs b/packages/feature/package/src/unused_export_report/cli/workflow.rs index 10c0e5fc7..947a03b13 100644 --- a/packages/feature/package/src/unused_export_report/cli/workflow.rs +++ b/packages/feature/package/src/unused_export_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unused_export_report::cli::args::UnusedExportReportArgs; use crate::unused_export_report::cli::render::print_unused_export_report; @@ -6,17 +6,25 @@ use crate::unused_export_report::usecase::{ UnusedExportPolicyOptions, analyze_unused_exports, collect_declared_exports, collect_referenced_symbols, evaluate_unused_export_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn unused_export_report(args: UnusedExportReportArgs) -> CommandResult { - let mut declared = Vec::new(); - let mut referenced = Vec::new(); - - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_exports(file, dialect, &tree)?); - referenced.extend(collect_referenced_symbols(dialect, &tree)?); + let declared = collect_declared_exports(file, dialect, &tree)?; + let referenced = collect_referenced_symbols(dialect, &tree)?; + CliResult::Ok((declared, referenced)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (declared_lists, referenced_lists): (Vec<_>, Vec<_>) = + analysis.succeeded.into_iter().unzip(); + let declared: Vec<_> = declared_lists.into_iter().flatten().collect(); + let referenced: Vec<_> = referenced_lists.into_iter().flatten().collect(); let summary = analyze_unused_exports(&declared, &referenced); let policy = evaluate_unused_export_policy( diff --git a/packages/feature/package/src/unused_nickname_report/cli/workflow.rs b/packages/feature/package/src/unused_nickname_report/cli/workflow.rs index e3e2fa022..4bb7411b4 100644 --- a/packages/feature/package/src/unused_nickname_report/cli/workflow.rs +++ b/packages/feature/package/src/unused_nickname_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unused_nickname_report::cli::args::UnusedNicknameReportArgs; use crate::unused_nickname_report::cli::render::print_unused_nickname_report; @@ -6,17 +6,25 @@ use crate::unused_nickname_report::usecase::{ UnusedNicknamePolicyOptions, analyze_unused_nicknames, collect_declared_nicknames, collect_referenced_package_names, evaluate_unused_nickname_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn unused_nickname_report(args: UnusedNicknameReportArgs) -> CommandResult { - let mut declared = Vec::new(); - let mut referenced = Vec::new(); - - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_nicknames(file, dialect, &tree)?); - referenced.extend(collect_referenced_package_names(dialect, &tree)?); + let declared = collect_declared_nicknames(file, dialect, &tree)?; + let referenced = collect_referenced_package_names(dialect, &tree)?; + CliResult::Ok((declared, referenced)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (declared_lists, referenced_lists): (Vec<_>, Vec<_>) = + analysis.succeeded.into_iter().unzip(); + let declared: Vec<_> = declared_lists.into_iter().flatten().collect(); + let referenced: Vec<_> = referenced_lists.into_iter().flatten().collect(); let summary = analyze_unused_nicknames(&declared, &referenced); let policy = evaluate_unused_nickname_policy( diff --git a/packages/feature/package/src/unused_package_report/cli/workflow.rs b/packages/feature/package/src/unused_package_report/cli/workflow.rs index b7416060c..8870062d3 100644 --- a/packages/feature/package/src/unused_package_report/cli/workflow.rs +++ b/packages/feature/package/src/unused_package_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; use crate::unused_package_report::cli::args::UnusedPackageReportArgs; use crate::unused_package_report::cli::render::print_unused_package_report; @@ -6,17 +6,25 @@ use crate::unused_package_report::usecase::{ UnusedPackagePolicyOptions, analyze_unused_packages, collect_declared_packages, collect_referenced_package_names, evaluate_unused_package_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn unused_package_report(args: UnusedPackageReportArgs) -> CommandResult { - let mut declared = Vec::new(); - let mut referenced = Vec::new(); - - for file in &args.files { + let analysis = analyze_files_raw(&args.files, |file| { let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_packages(file, dialect, &tree)?); - referenced.extend(collect_referenced_package_names(dialect, &tree)?); + let declared = collect_declared_packages(file, dialect, &tree)?; + let referenced = collect_referenced_package_names(dialect, &tree)?; + CliResult::Ok((declared, referenced)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (declared_lists, referenced_lists): (Vec<_>, Vec<_>) = + analysis.succeeded.into_iter().unzip(); + let declared: Vec<_> = declared_lists.into_iter().flatten().collect(); + let referenced: Vec<_> = referenced_lists.into_iter().flatten().collect(); let summary = analyze_unused_packages(&declared, &referenced); let policy = evaluate_unused_package_policy( diff --git a/packages/feature/package/src/use_widening_report/cli/workflow.rs b/packages/feature/package/src/use_widening_report/cli/workflow.rs index a3c8d875a..6850596f7 100644 --- a/packages/feature/package/src/use_widening_report/cli/workflow.rs +++ b/packages/feature/package/src/use_widening_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::use_widening_report::cli::args::UseWideningReportArgs; use crate::use_widening_report::cli::render::print_use_widening_report; @@ -9,11 +11,14 @@ use crate::use_widening_report::usecase::{build_use_widening_report, evaluate_fa pub fn use_widening_report(args: UseWideningReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_use_widening_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_use_widening_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_use_policy(args.fail_on_use, &reports); let passed = policy.passed; diff --git a/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs index 739e47e5b..c62687903 100644 --- a/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs @@ -6,19 +6,23 @@ use crate::call_cycle_report::usecase::{ CallCyclePolicyOptions, analyze_call_cycles, evaluate_call_cycle_policy, }; use crate::call_graph_report::usecase::{CallGraphReportSource, build_call_graph_report}; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::CliResult; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn call_cycle_report(args: CallCycleReportArgs) -> CommandResult { - let mut sources = Vec::with_capacity(args.files.len()); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - sources.push(CallGraphReportSource { + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(CallGraphReportSource { path: file.clone(), dialect, - tree, - }); + tree: tree.clone(), + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let sources = analysis.succeeded; let report = build_call_graph_report(sources, false, None)?; let summary = analyze_call_cycles(&report.files); diff --git a/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs index 3d0f0f28d..c5244b67e 100644 --- a/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs @@ -6,22 +6,26 @@ use crate::call_graph_report::usecase::{ CallGraphPolicyOptions, CallGraphReportSource, build_call_graph_report, evaluate_call_graph_policy, }; +use paredit_core_cli::CliResult; use paredit_core_cli::report::graph::print_graph; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn call_graph(args: CallGraphArgs) -> CommandResult { let symbol = args.symbol.as_ref(); - let mut sources = Vec::with_capacity(args.files.len()); - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - - sources.push(CallGraphReportSource { + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(CallGraphReportSource { path: file.clone(), dialect, - tree, - }); + tree: tree.clone(), + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let sources = analysis.succeeded; let report = build_call_graph_report(sources, args.include_external, symbol)?; let policy = evaluate_call_graph_policy( diff --git a/packages/feature/project-analysis/src/call_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_report/cli/workflow.rs index 9de05cd99..c0b60cbb8 100644 --- a/packages/feature/project-analysis/src/call_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_report/cli/workflow.rs @@ -4,26 +4,29 @@ use crate::call_report::cli::{ args::CallReportArgs, render::print_call_report, types::CallReportFile, }; use crate::call_report::usecase::build_call_report; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use crate::error::ProjectAnalysisResult; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn call_report(args: CallReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { let calls = build_call_report( - &tree, + tree, dialect, args.symbol.as_ref(), args.include_definitions, )?; - - reports.push(CallReportFile { + ProjectAnalysisResult::Ok(CallReportFile { path: file.clone(), dialect, calls, - }); + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let call_count = reports .iter() diff --git a/packages/feature/project-analysis/src/class_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/class_cycle_report/cli/workflow.rs index 03b88394d..f74fffdab 100644 --- a/packages/feature/project-analysis/src/class_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/class_cycle_report/cli/workflow.rs @@ -6,15 +6,18 @@ use crate::class_cycle_report::usecase::{ ClassCyclePolicyOptions, analyze_class_cycles, collect_class_inheritance_edges, evaluate_class_cycle_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn class_cycle_report(args: ClassCycleReportArgs) -> CommandResult { - let mut edges = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - edges.extend(collect_class_inheritance_edges(dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |_file, dialect, tree, _| { + collect_class_inheritance_edges(dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let edges: Vec<(String, String)> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_class_cycles(&edges); let policy = diff --git a/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs b/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs index 0ba5b3f65..7f26a8d8b 100644 --- a/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; use std::collections::BTreeSet; use std::fs; @@ -13,13 +13,16 @@ use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_work pub fn complexity_report(args: ComplexityReportArgs) -> CommandResult { let files = expand_complexity_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_input, dialect, tree) = - read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_complexity_report(file.clone(), dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + build_complexity_report(file.clone(), dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_complexity_report_policy( ComplexityReportPolicyOptions::new(args.fail_on_max_depth), diff --git a/packages/feature/project-analysis/src/error.rs b/packages/feature/project-analysis/src/error.rs index ac131b11a..01f32bc57 100644 --- a/packages/feature/project-analysis/src/error.rs +++ b/packages/feature/project-analysis/src/error.rs @@ -58,6 +58,14 @@ pub enum ProjectAnalysisError { #[error(transparent)] Workspace(#[from] WorkspaceAnalysisError), + + // `analyze_files` reads and parses each file itself, ahead of the + // per-file analysis this crate contributes; this is that read/parse + // failure crossing into the closure's own error type so a single + // unreadable file among many is data for the report rather than an + // error `analyze_files` has no vocabulary to carry. + #[error(transparent)] + Io(#[from] paredit_core_cli::CliError), } /// The result type the project-analysis passes return. @@ -75,6 +83,7 @@ paredit_core_cli::impl_classified_refusal!(ProjectAnalysisError, |error| match e ProjectAnalysisError::Definitions(definitions) => paredit_feature_remove_unused::error::code_of(definitions), ProjectAnalysisError::Workspace(_) => paredit_core_cli::diagnosis::ErrorCode::RefusalWorkspace, + ProjectAnalysisError::Io(io) => paredit_core_cli::diagnosis::code_for_cli_error(io), }); // A workspace analysis failure names the file it stopped on; the failure diff --git a/packages/feature/project-analysis/src/impact_report/cli/workflow.rs b/packages/feature/project-analysis/src/impact_report/cli/workflow.rs index 6c0ef0be2..1e45f632d 100644 --- a/packages/feature/project-analysis/src/impact_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/impact_report/cli/workflow.rs @@ -6,7 +6,9 @@ use crate::impact_report::usecase::{ evaluate_impact_report_policy, impact_risks, impact_status_counts, summarize_impact_reports, }; use paredit_core_cli::args::DialectArg; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; use paredit_core_cli::{CliResult, CommandResult}; use paredit_core_syntax::sexpr::SymbolName; use std::path::PathBuf; @@ -53,17 +55,20 @@ pub fn collect_impact_reports( dialect_override: Option, symbol: &SymbolName, ) -> CliResult> { - let mut sources = Vec::with_capacity(files.len()); - - for file in files { + let analysis = analyze_files_raw(files, |file| { let (_input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), dialect_override)?; - sources.push(ImpactReportSource { + CliResult::Ok(ImpactReportSource { path: file.clone(), dialect, tree, - }); + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let sources = analysis.succeeded; Ok(build_impact_reports(sources, symbol)?) } diff --git a/packages/feature/project-analysis/src/naming_report/cli/workflow.rs b/packages/feature/project-analysis/src/naming_report/cli/workflow.rs index 321327335..ca01ae3a6 100644 --- a/packages/feature/project-analysis/src/naming_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/naming_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; use std::collections::BTreeSet; use std::fs; @@ -13,13 +13,16 @@ use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_work pub fn naming_report(args: NamingReportArgs) -> CommandResult { let files = expand_naming_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_input, dialect, tree) = - read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_naming_report(file.clone(), dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + build_naming_report(file.clone(), dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_naming_report_policy( NamingReportPolicyOptions::new(args.fail_on_non_idiomatic), diff --git a/packages/feature/project-analysis/src/package_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/package_cycle_report/cli/workflow.rs index e5446ab4a..dcf8720d2 100644 --- a/packages/feature/project-analysis/src/package_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/package_cycle_report/cli/workflow.rs @@ -6,15 +6,18 @@ use crate::package_cycle_report::usecase::{ PackageCyclePolicyOptions, analyze_package_cycles, collect_package_dependency_edges, evaluate_package_cycle_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn package_cycle_report(args: PackageCycleReportArgs) -> CommandResult { - let mut edges = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - edges.extend(collect_package_dependency_edges(dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |_file, dialect, tree, _| { + collect_package_dependency_edges(dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let edges: Vec<(String, String)> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_package_cycles(&edges); let policy = diff --git a/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs b/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs index 88ae280ea..296927775 100644 --- a/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs @@ -6,19 +6,23 @@ use crate::reachability_report::cli::render::print_reachability_report; use crate::reachability_report::usecase::{ ReachabilityReportPolicyOptions, analyze_reachability, evaluate_reachability_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::CliResult; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn reachability_report(args: ReachabilityReportArgs) -> CommandResult { - let mut sources = Vec::with_capacity(args.files.len()); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - sources.push(CallGraphReportSource { + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(CallGraphReportSource { path: file.clone(), dialect, - tree, - }); + tree: tree.clone(), + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let sources = analysis.succeeded; let report = build_call_graph_report(sources, false, None)?; let summary = analyze_reachability(&report.files); diff --git a/packages/feature/project-analysis/src/redefinition_report/cli/workflow.rs b/packages/feature/project-analysis/src/redefinition_report/cli/workflow.rs index 9edd5d241..a2c64bc30 100644 --- a/packages/feature/project-analysis/src/redefinition_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/redefinition_report/cli/workflow.rs @@ -6,15 +6,18 @@ use crate::redefinition_report::usecase::{ RedefinitionPolicyOptions, analyze_redefinitions, collect_declared_definitions, evaluate_redefinition_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn redefinition_report(args: RedefinitionReportArgs) -> CommandResult { - let mut declared = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_definitions(file, dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + collect_declared_definitions(file, dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let declared: Vec<_> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_redefinitions(&declared); let policy = evaluate_redefinition_policy( diff --git a/packages/feature/project-analysis/src/signature_report/cli/workflow.rs b/packages/feature/project-analysis/src/signature_report/cli/workflow.rs index 4b014d026..8b6ed64b8 100644 --- a/packages/feature/project-analysis/src/signature_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/signature_report/cli/workflow.rs @@ -5,20 +5,25 @@ use crate::signature_report::cli::render::print_signature_report; use crate::signature_report::usecase::{ SignatureReportSource, build_signature_reports, evaluate_signature_report_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::CliResult; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn signature_report(args: SignatureReportArgs) -> CommandResult { let symbol = args.symbol.as_ref(); - let mut sources = Vec::with_capacity(args.files.len()); - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - sources.push(SignatureReportSource { + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(SignatureReportSource { path: file.clone(), dialect, - tree, - }); + tree: tree.clone(), + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let sources = analysis.succeeded; let reports = build_signature_reports(sources, symbol)?; let policy = evaluate_signature_report_policy( diff --git a/packages/feature/project-analysis/src/struct_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/struct_cycle_report/cli/workflow.rs index 183aea7aa..58e614547 100644 --- a/packages/feature/project-analysis/src/struct_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/struct_cycle_report/cli/workflow.rs @@ -6,15 +6,18 @@ use crate::struct_cycle_report::usecase::{ StructCyclePolicyOptions, analyze_struct_cycles, collect_struct_inheritance_edges, evaluate_struct_cycle_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn struct_cycle_report(args: StructCycleReportArgs) -> CommandResult { - let mut edges = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - edges.extend(collect_struct_inheritance_edges(dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |_file, dialect, tree, _| { + collect_struct_inheritance_edges(dialect, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let edges: Vec<(String, String)> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_struct_cycles(&edges); let policy = diff --git a/packages/feature/project-analysis/src/system_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/system_cycle_report/cli/workflow.rs index 1882210b6..ee5f2f587 100644 --- a/packages/feature/project-analysis/src/system_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/system_cycle_report/cli/workflow.rs @@ -1,20 +1,24 @@ use paredit_core_cli::CommandResult; +use crate::error::ProjectAnalysisResult; use crate::system_cycle_report::cli::args::SystemCycleReportArgs; use crate::system_cycle_report::cli::render::print_system_cycle_report; use crate::system_cycle_report::usecase::{ SystemCyclePolicyOptions, analyze_system_cycles, build_system_dependency_edges, evaluate_system_cycle_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn system_cycle_report(args: SystemCycleReportArgs) -> CommandResult { - let mut edges = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - edges.extend(build_system_dependency_edges(&tree, dialect)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |_file, dialect, tree, _| { + ProjectAnalysisResult::Ok(build_system_dependency_edges(tree, dialect)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let edges: Vec<(String, String)> = analysis.succeeded.into_iter().flatten().collect(); let summary = analyze_system_cycles(&edges); let policy = diff --git a/packages/feature/project-analysis/src/undefined_package_report/cli/workflow.rs b/packages/feature/project-analysis/src/undefined_package_report/cli/workflow.rs index ee0dd1513..4d7d5a079 100644 --- a/packages/feature/project-analysis/src/undefined_package_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/undefined_package_report/cli/workflow.rs @@ -1,22 +1,28 @@ use paredit_core_cli::CommandResult; +use crate::error::ProjectAnalysisResult; use crate::undefined_package_report::cli::args::UndefinedPackageReportArgs; use crate::undefined_package_report::cli::render::print_undefined_package_report; use crate::undefined_package_report::usecase::{ UndefinedPackagePolicyOptions, analyze_undefined_packages, collect_declared_package_names, collect_in_package_references, evaluate_undefined_package_policy, }; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; pub fn undefined_package_report(args: UndefinedPackageReportArgs) -> CommandResult { - let mut declared = Vec::new(); - let mut referenced = Vec::new(); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - declared.extend(collect_declared_package_names(dialect, &tree)?); - referenced.extend(collect_in_package_references(file, dialect, &tree)?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { + let declared = collect_declared_package_names(dialect, tree)?; + let referenced = collect_in_package_references(file, dialect, tree)?; + ProjectAnalysisResult::Ok((declared, referenced)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let (declared, referenced): (Vec<_>, Vec<_>) = analysis.succeeded.into_iter().unzip(); + let declared: Vec<_> = declared.into_iter().flatten().collect(); + let referenced: Vec<_> = referenced.into_iter().flatten().collect(); let summary = analyze_undefined_packages(&declared, &referenced); let policy = evaluate_undefined_package_policy( diff --git a/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs b/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs index a6225675c..5ed0929f2 100644 --- a/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs @@ -1,4 +1,4 @@ -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; use std::collections::BTreeSet; use std::fs; @@ -14,17 +14,16 @@ use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_work pub fn unused_local_callable_report(args: UnusedLocalCallableReportArgs) -> CommandResult { let files = expand_unused_local_callable_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unused_local_callable_report( - file.clone(), - dialect, - &input.text, - &tree, - )?); + // A file that will not parse is reported, not fatal — see `query find`. + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { + build_unused_local_callable_report(file.clone(), dialect, &input.text, tree) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_unused_local_callable_policy( UnusedLocalCallablePolicyOptions::new(args.fail_on_unused), diff --git a/packages/feature/project-inventory/src/api_diff_report/cli/workflow.rs b/packages/feature/project-inventory/src/api_diff_report/cli/workflow.rs index 35632dd7f..c148a80e7 100644 --- a/packages/feature/project-inventory/src/api_diff_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/api_diff_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::{CliError, CommandResult}; +use paredit_core_cli::{CliError, CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::api_diff_report::cli::args::{ApiDiffReportArgs, IntendedBump}; use crate::api_diff_report::cli::render::print_api_diff_report; @@ -21,11 +23,14 @@ pub fn api_diff_report(args: ApiDiffReportArgs) -> CommandResult { let baseline = read_baseline(&document); let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_api_diff_report(file, dialect, &tree, &baseline)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_api_diff_report(file, dialect, tree, &baseline)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_api_diff_policy(args.intended_bump.map(IntendedBump::label), &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/api_surface_report/cli/workflow.rs b/packages/feature/project-inventory/src/api_surface_report/cli/workflow.rs index efa4b6cc0..f526207bf 100644 --- a/packages/feature/project-inventory/src/api_surface_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/api_surface_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::api_surface_report::cli::args::ApiSurfaceReportArgs; use crate::api_surface_report::cli::render::print_undefined_export_report; @@ -11,11 +13,14 @@ use crate::api_surface_report::usecase::{ pub fn api_surface_report(args: ApiSurfaceReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_api_surface_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_api_surface_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_undefined_export_policy(args.fail_on_undefined_export, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/blame_report/cli/workflow.rs b/packages/feature/project-inventory/src/blame_report/cli/workflow.rs index 2999c97f8..235cac388 100644 --- a/packages/feature/project-inventory/src/blame_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/blame_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::blame_report::cli::args::BlameReportArgs; use crate::blame_report::cli::render::print_blame_report; @@ -9,14 +11,17 @@ use crate::blame_report::usecase::{build_blame_report, evaluate_blame_policy, me pub fn blame_report(args: BlameReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { // One `git blame` per file, run in the file's own directory so a report // spanning several repositories answers for each of them. let blame = measure_blame(&file.canonicalize().unwrap_or_else(|_| file.clone())); - reports.push(build_blame_report(file, dialect, &tree, &blame)); + CliResult::Ok(build_blame_report(file, dialect, tree, &blame)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_blame_policy(args.fail_on_unattributed, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/external_system_report/cli/workflow.rs b/packages/feature/project-inventory/src/external_system_report/cli/workflow.rs index 495330fc2..e29570c96 100644 --- a/packages/feature/project-inventory/src/external_system_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/external_system_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::external_system_report::cli::args::ExternalSystemReportArgs; use crate::external_system_report::cli::render::print_external_report; @@ -11,11 +13,14 @@ use crate::external_system_report::usecase::{ pub fn external_system_report(args: ExternalSystemReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_external_system_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_external_system_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_external_policy(args.fail_on_external, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/keyword_arity_report/cli/workflow.rs b/packages/feature/project-inventory/src/keyword_arity_report/cli/workflow.rs index ad6aab8c1..ed5421f3a 100644 --- a/packages/feature/project-inventory/src/keyword_arity_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/keyword_arity_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::keyword_arity_report::cli::args::KeywordArityReportArgs; use crate::keyword_arity_report::cli::render::print_fault_report; @@ -11,11 +13,14 @@ use crate::keyword_arity_report::usecase::{ pub fn keyword_arity_report(args: KeywordArityReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_keyword_arity_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_keyword_arity_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_fault_policy(args.fail_on_fault, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/license_header_report/cli/workflow.rs b/packages/feature/project-inventory/src/license_header_report/cli/workflow.rs index 8b804636e..9c1bd802c 100644 --- a/packages/feature/project-inventory/src/license_header_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/license_header_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::license_header_report::cli::args::LicenseHeaderReportArgs; use crate::license_header_report::cli::render::print_license_header_report; @@ -11,11 +13,14 @@ use crate::license_header_report::usecase::{ pub fn license_header_report(args: LicenseHeaderReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_license_header_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_license_header_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let mut reports = analysis.succeeded; apply_header_consistency(&mut reports); diff --git a/packages/feature/project-inventory/src/license_report/cli/workflow.rs b/packages/feature/project-inventory/src/license_report/cli/workflow.rs index e179dbf20..cc3fc4f21 100644 --- a/packages/feature/project-inventory/src/license_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/license_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::license_report::cli::args::LicenseReportArgs; use crate::license_report::cli::render::print_review_report; @@ -9,11 +11,14 @@ use crate::license_report::usecase::{build_license_report, evaluate_fail_on_revi pub fn license_report(args: LicenseReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_license_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_license_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_review_policy(args.fail_on_review, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/serial_consistency_report/cli/workflow.rs b/packages/feature/project-inventory/src/serial_consistency_report/cli/workflow.rs index f226433dc..6d5ee8d1c 100644 --- a/packages/feature/project-inventory/src/serial_consistency_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/serial_consistency_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::serial_consistency_report::cli::args::SerialConsistencyReportArgs; use crate::serial_consistency_report::cli::render::print_fault_report; @@ -11,11 +13,14 @@ use crate::serial_consistency_report::usecase::{ pub fn serial_consistency_report(args: SerialConsistencyReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_serial_consistency_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_serial_consistency_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_fault_policy(args.fail_on_fault, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/symbol_index_report/cli/workflow.rs b/packages/feature/project-inventory/src/symbol_index_report/cli/workflow.rs index 31a891c54..5a14ed6d8 100644 --- a/packages/feature/project-inventory/src/symbol_index_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/symbol_index_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::symbol_index_report::cli::args::SymbolIndexReportArgs; use crate::symbol_index_report::cli::render::print_external_report; @@ -11,11 +13,14 @@ use crate::symbol_index_report::usecase::{ pub fn symbol_index_report(args: SymbolIndexReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_symbol_index_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_symbol_index_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_external_policy(args.fail_on_external, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs b/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs index f4bde5a53..02b6df88e 100644 --- a/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs @@ -1,6 +1,9 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{matching_symbol_occurrences, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, matching_symbol_occurrences, note_partial_file_failures, + read_input_dialect_and_tree, total_file_failure, +}; use super::args::{SymbolQueryArgs, SymbolReportArgs}; use super::render::{print_symbol_occurrences, print_symbol_report}; @@ -23,12 +26,9 @@ fn require_occurrences(found: usize, required: Option) -> CommandResult { } pub fn symbol_report(args: SymbolReportArgs) -> CommandResult { - let mut reports = Vec::with_capacity(args.files.len()); - - for file in &args.files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { let outline = tree.outline(|head| dialect.is_definition_head(head)); - let occurrences = matching_symbol_occurrences(&tree, &args.symbol) + let occurrences = matching_symbol_occurrences(tree, &args.symbol) .into_iter() .map(|occurrence| SymbolReportOccurrence { path: occurrence.path.to_string(), @@ -46,12 +46,17 @@ pub fn symbol_report(args: SymbolReportArgs) -> CommandResult { }) .collect::>(); - reports.push(SymbolReportFile { + CliResult::Ok(SymbolReportFile { path: file.clone(), dialect, occurrences, - }); + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let occurrence_count = reports .iter() diff --git a/packages/feature/project-inventory/src/test_map_report/cli/workflow.rs b/packages/feature/project-inventory/src/test_map_report/cli/workflow.rs index 9d847a547..4d514cbd0 100644 --- a/packages/feature/project-inventory/src/test_map_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/test_map_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::test_map_report::cli::args::TestMapReportArgs; use crate::test_map_report::cli::render::print_untested_report; @@ -9,11 +11,14 @@ use crate::test_map_report::usecase::{build_test_map_report, evaluate_fail_on_un pub fn test_map_report(args: TestMapReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_test_map_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_test_map_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_untested_policy(args.fail_on_untested, &reports); let passed = policy.passed; diff --git a/packages/feature/project-inventory/src/unreachable_expression_report/cli/workflow.rs b/packages/feature/project-inventory/src/unreachable_expression_report/cli/workflow.rs index e70bb555b..aec2ea659 100644 --- a/packages/feature/project-inventory/src/unreachable_expression_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/unreachable_expression_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::unreachable_expression_report::cli::args::UnreachableExpressionReportArgs; use crate::unreachable_expression_report::cli::render::print_unreachable_report; @@ -11,11 +13,14 @@ use crate::unreachable_expression_report::usecase::{ pub fn unreachable_expression_report(args: UnreachableExpressionReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_unreachable_expression_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_unreachable_expression_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_unreachable_policy(args.fail_on_unreachable, &reports); let passed = policy.passed; diff --git a/packages/feature/refactor-workflow/src/refactor/cli/manifest/check.rs b/packages/feature/refactor-workflow/src/refactor/cli/manifest/check.rs index c96dd1acc..161efe06b 100644 --- a/packages/feature/refactor-workflow/src/refactor/cli/manifest/check.rs +++ b/packages/feature/refactor-workflow/src/refactor/cli/manifest/check.rs @@ -24,6 +24,11 @@ pub fn build_refactor_check_result( let manifest_policy_passed = manifest.policy_passed; let manifest_outputs_parse = manifest.all_outputs_parse; + // Deliberately not converted to the `analyze_files_raw` partial-failure + // pattern used elsewhere in this branch: fail-fast is load-bearing here, + // since `can_apply` gates whether `refactor apply` is safe to run, and a + // manifest entry that couldn't even be read must not silently drop out of + // that verdict rather than fail it. let mut files = Vec::with_capacity(manifest.files.len()); let mut source_bytes = 0_u64; diff --git a/packages/feature/refactor-workflow/src/refactor_checkpoint/cli/workflow.rs b/packages/feature/refactor-workflow/src/refactor_checkpoint/cli/workflow.rs index c36040538..c2926ac6b 100644 --- a/packages/feature/refactor-workflow/src/refactor_checkpoint/cli/workflow.rs +++ b/packages/feature/refactor-workflow/src/refactor_checkpoint/cli/workflow.rs @@ -2,6 +2,7 @@ use paredit_core_cli::ArgumentError; use paredit_core_cli::CommandResult; use paredit_core_cli::diagnosis::ErrorCode; use paredit_core_cli::error::FeatureRefusal; +use paredit_core_cli::shared::analyze_files_raw; use paredit_core_safety::journal::{UndoJournal, UndoJournalFile}; @@ -66,6 +67,10 @@ pub fn create_checkpoint(args: CreateCheckpointArgs) -> CommandResult { .map(RefactorRootGuard::new) .transpose()?; + // Deliberately not converted to the `analyze_files_raw` partial-failure + // pattern used elsewhere in this branch: fail-fast is load-bearing here, + // since a checkpoint must cover every requested file or record none at + // all, not silently omit one a later restore would then have no record of. let mut entries = Vec::with_capacity(args.files.len()); let mut resolved_paths = Vec::with_capacity(args.files.len()); for path in &args.files { @@ -157,23 +162,48 @@ pub fn restore_checkpoint(args: RestoreCheckpointArgs) -> CommandResult { .map(RefactorRootGuard::new) .transpose()?; - let mut files = Vec::with_capacity(checkpoint.journal.files.len()); - for entry in &checkpoint.journal.files { - let (matches_checkpoint, blocked_reason) = - match read_refactor_manifest_source(&entry.path, root_guard.as_ref()) { - Ok((_, current, _)) => match entry.restore(¤t) { + // The read is the I/O-bound half and is parallelized; `entry.restore` + // (a hash comparison) is cheap enough to stay serial in the zip below. The + // closure never fails — an unreadable file is a blocked entry, not a + // dropped one — so `analyze_files_raw`'s order-preserving guarantee means + // `read_results.succeeded` lines up 1:1 with `checkpoint.journal.files`. + let paths = checkpoint + .journal + .files + .iter() + .map(|entry| entry.path.clone()) + .collect::>(); + let read_results = analyze_files_raw(&paths, |path| { + Result::<_, std::convert::Infallible>::Ok( + match read_refactor_manifest_source(path, root_guard.as_ref()) { + Ok((_, current, _)) => Ok(current), + Err(error) => Err(format!("{error:#}")), + }, + ) + }); + debug_assert!(read_results.failed.is_empty(), "the read never fails"); + + let mut files = checkpoint + .journal + .files + .iter() + .zip(read_results.succeeded) + .map(|(entry, read_result)| { + let (matches_checkpoint, blocked_reason) = match read_result { + Ok(current) => match entry.restore(¤t) { Ok(_) => (true, None), Err(error) => (false, Some(error.to_string())), }, - Err(error) => (false, Some(format!("{error:#}"))), + Err(error) => (false, Some(error)), }; - files.push(CheckpointRestoreFileResult { - path: entry.path.clone(), - matches_checkpoint, - restored: false, - blocked_reason, - }); - } + CheckpointRestoreFileResult { + path: entry.path.clone(), + matches_checkpoint, + restored: false, + blocked_reason, + } + }) + .collect::>(); let blocked_file_count = files.iter().filter(|file| !file.matches_checkpoint).count(); let restorable_file_count = files.len() - blocked_file_count; diff --git a/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs b/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs index c0230d768..f55d4b966 100644 --- a/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs +++ b/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs @@ -7,40 +7,48 @@ use crate::remove_unused_definition::usecase::{ RemoveUnusedDefinitionInputFile, RemoveUnusedDefinitionsRequest, UnusedDefinitionDefinition, plan_remove_unused_definitions, }; -use paredit_core_cli::shared::{read_input_dialect_and_tree, write_files_with_rollback}; +use paredit_core_cli::shared::{ + analyze_files, note_partial_file_failures, total_file_failure, write_files_with_rollback, +}; +use paredit_feature_package::error::PackageCommandError; use paredit_feature_package::package_report::usecase::build_package_report; pub fn remove_unused_definitions(args: RemoveUnusedDefinitionsArgs) -> CliResult<()> { - let mut input_files = Vec::with_capacity(args.files.len()); - let mut package_definitions = Vec::new(); - - for file in &args.files { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let (package, definitions) = collect_definition_forms(&tree, dialect)?; - let package_report = build_package_report(&tree, dialect).map_err(|source| { - paredit_feature_package::error::PackageCommandError::Inspect { + let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, input| { + let (package, definitions) = collect_definition_forms(tree, dialect)?; + let package_report = + build_package_report(tree, dialect).map_err(|source| PackageCommandError::Inspect { path: file.display().to_string(), source, - } - })?; - package_definitions.extend(package_report.defpackages); + })?; - input_files.push(RemoveUnusedDefinitionInputFile { - path: file.clone(), - dialect, - package, - definitions: definitions - .iter() - .map(to_unused_definition_definition) - .collect(), - atoms: tree.atom_occurrences(), - text: input.text, - }); + CliResult::Ok(( + RemoveUnusedDefinitionInputFile { + path: file.clone(), + dialect, + package, + definitions: definitions + .iter() + .map(to_unused_definition_definition) + .collect(), + atoms: tree.atom_occurrences(), + text: input.text.clone(), + root_view: tree.root_view(), + }, + package_report.defpackages, + )) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + + let (input_files, package_definitions): (Vec<_>, Vec<_>) = + analysis.succeeded.into_iter().unzip(); let plan = plan_remove_unused_definitions(RemoveUnusedDefinitionsRequest { files: input_files, - package_definitions, + package_definitions: package_definitions.into_iter().flatten().collect(), include_protected: args.include_protected, include_exported: args.include_exported, })?; diff --git a/packages/feature/remove-unused/src/definition_report/cli/workflow.rs b/packages/feature/remove-unused/src/definition_report/cli/workflow.rs index 53671afff..f7fa106bd 100644 --- a/packages/feature/remove-unused/src/definition_report/cli/workflow.rs +++ b/packages/feature/remove-unused/src/definition_report/cli/workflow.rs @@ -1,10 +1,8 @@ -use paredit_core_cli::args::SourceInput; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_file_failure}; use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_syntax::sexpr::SyntaxTree; use std::collections::BTreeSet; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use super::args::{DefinitionReportArgs, UnusedDefinitionReportArgs}; use super::render::{print_definition_report, print_unused_definition_report}; @@ -16,29 +14,32 @@ use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_work pub fn definition_report(args: DefinitionReportArgs) -> CliResult<()> { let files = expand_definition_report_inputs(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - - for file in &files { - let (file, _input, dialect, tree) = load_definition_input(file, args.dialect)?; - reports.push(build_definition_report(file, dialect, &tree)?); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { + CliResult::Ok(build_definition_report(file.clone(), dialect, tree)?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); - print_definition_report(&reports, args.output) + print_definition_report(&analysis.succeeded, args.output) } pub fn unused_definition_report(args: UnusedDefinitionReportArgs) -> CommandResult { let files = expand_definition_report_inputs(&args.files, args.dialect)?; - let mut parsed = Vec::with_capacity(files.len()); - - for file in &files { - let (file, input, dialect, tree) = load_definition_input(file, args.dialect)?; - parsed.push(build_parsed_definition_file( - file, + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { + CliResult::Ok(build_parsed_definition_file( + file.clone(), dialect, - &tree, + tree, &input.text, - )?); + )?) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let parsed = analysis.succeeded; let reports = collect_unused_definition_candidates(&parsed)?; let policy = evaluate_unused_definition_policy( @@ -96,17 +97,3 @@ fn push_unique(expanded: &mut Vec, seen: &mut BTreeSet, path: expanded.push(path); } } - -fn load_definition_input( - file: &Path, - dialect: Option, -) -> CliResult<( - PathBuf, - SourceInput, - paredit_core_syntax::dialect::Dialect, - SyntaxTree, -)> { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.to_path_buf()), dialect)?; - - Ok((file.to_path_buf(), input, dialect, tree)) -} diff --git a/packages/feature/remove-unused/src/definition_report/domain.rs b/packages/feature/remove-unused/src/definition_report/domain.rs index 0789624c9..edf91c05a 100644 --- a/packages/feature/remove-unused/src/definition_report/domain.rs +++ b/packages/feature/remove-unused/src/definition_report/domain.rs @@ -93,6 +93,13 @@ pub struct ParsedDefinitionFile { pub definitions: Vec, pub atoms: Vec, pub text: String, + /// The root view from the parse this file was already loaded with. + /// + /// Kept alongside `text` rather than instead of it: `text` is still read + /// directly for substring reference-needle scans, but this is what saves + /// `collect_unused_definition_candidates` from re-parsing `text` from + /// scratch just to get a view it already had once. + pub root_view: ExpressionView, } #[derive(Debug, Clone)] @@ -157,6 +164,7 @@ pub fn build_parsed_definition_file( definitions, atoms: tree.atom_occurrences(), text: text.to_owned(), + root_view: tree.root_view(), }) } @@ -172,26 +180,14 @@ pub fn collect_unused_definition_candidates( } } - let views: Vec> = files - .iter() - .map(|file| { - SyntaxTree::parse_with_dialect(&file.text, file.dialect) - .map_err(|source| RemoveUnusedError::ParseFailed { - path: file.path.display().to_string(), - source, - }) - .map(|tree| Some(tree.root_view())) - }) - .collect::>()?; + let views: Vec<&ExpressionView> = files.iter().map(|file| &file.root_view).collect(); let package_form_spans: Vec> = files .iter() - .enumerate() - .map(|(index, file)| { + .zip(&views) + .map(|(file, view)| { let mut spans = Vec::new(); - if let Some(view) = &views[index] { - collect_package_form_spans(file.dialect, view, &mut spans); - } + collect_package_form_spans(file.dialect, view, &mut spans); spans }) .collect(); @@ -199,9 +195,7 @@ pub fn collect_unused_definition_candidates( .iter() .map(|view| { let mut needles = HashSet::new(); - if let Some(view) = view { - collect_reference_needles(view, &mut needles); - } + collect_reference_needles(view, &mut needles); needles }) .collect(); @@ -255,7 +249,7 @@ pub fn collect_unused_definition_candidates( fn file_unused_definition_report( files: &[ParsedDefinitionFile], - views: &[Option], + views: &[&ExpressionView], package_form_spans: &[Vec], atom_needles: &[HashSet], file_index: usize, @@ -279,13 +273,10 @@ fn file_unused_definition_report( .enumerate() .flat_map(|(other_index, other)| { let mut spans = Vec::new(); - if let Some(view) = views[other_index] - .as_ref() - .filter(|_| atom_needles[other_index].contains(&needle)) - { + if atom_needles[other_index].contains(&needle) { collect_symbol_references( other.dialect, - view, + views[other_index], &symbol, &other.text, &mut spans, @@ -474,6 +465,16 @@ mod tests { } } + /// A placeholder root view for a fixture whose own text is deliberately + /// unparseable: the dialect check this test exercises rejects the file + /// before any view is ever read, so what is stored here is never + /// examined, and it need not correspond to `text`. + fn placeholder_root_view() -> ExpressionView { + SyntaxTree::parse_with_dialect("()", Dialect::CommonLisp) + .expect("placeholder must parse") + .root_view() + } + #[test] fn rejects_unknown_dialect_before_parsing_any_file() { let files = vec![ @@ -484,6 +485,7 @@ mod tests { definitions: Vec::new(), atoms: Vec::new(), text: "(defun broken ()".to_owned(), + root_view: placeholder_root_view(), }, ParsedDefinitionFile { path: PathBuf::from("unknown.lisp"), @@ -492,6 +494,7 @@ mod tests { definitions: Vec::new(), atoms: Vec::new(), text: "()".to_owned(), + root_view: placeholder_root_view(), }, ]; @@ -503,22 +506,6 @@ mod tests { ); } - #[test] - fn propagates_malformed_input_errors() { - let files = vec![ParsedDefinitionFile { - path: PathBuf::from("broken.lisp"), - dialect: Dialect::CommonLisp, - package: None, - definitions: Vec::new(), - atoms: Vec::new(), - text: "(defun broken ()".to_owned(), - }]; - - let error = collect_unused_definition_candidates(&files).expect_err("input must fail"); - - assert_eq!(error.to_string(), "failed to parse broken.lisp"); - } - #[test] fn parses_reader_syntax_with_the_input_dialect() { let text = "(defun el-reader () [?\\)])\n"; diff --git a/packages/feature/remove-unused/src/remove_unused_definition/domain/candidates.rs b/packages/feature/remove-unused/src/remove_unused_definition/domain/candidates.rs index 4431c9cf3..56d394954 100644 --- a/packages/feature/remove-unused/src/remove_unused_definition/domain/candidates.rs +++ b/packages/feature/remove-unused/src/remove_unused_definition/domain/candidates.rs @@ -8,7 +8,7 @@ use paredit_core_semantics::definition_reference::{ }; use paredit_core_syntax::common_lisp::common_lisp_symbol_reference_needle; use paredit_core_syntax::dialect::Dialect; -use paredit_core_syntax::sexpr::{ByteSpan, ExpressionView, SymbolName, SyntaxTree}; +use paredit_core_syntax::sexpr::{ByteSpan, ExpressionView, SymbolName}; #[derive(Debug)] pub struct UnusedDefinitionItem { @@ -36,22 +36,12 @@ pub fn collect_unused_definition_candidates( } } - let parsed_files = files - .iter() - .map(|file| -> RemoveUnusedResult<_> { - let tree = - SyntaxTree::parse_with_dialect(&file.text, file.dialect).map_err(|source| { - RemoveUnusedError::ParseFailed { - path: file.path.display().to_string(), - source, - } - })?; - Ok((file, tree.root_view())) - }) - .collect::>>()?; + let parsed_files: Vec<(&RemoveUnusedDefinitionInputFile, &ExpressionView)> = + files.iter().map(|file| (file, &file.root_view)).collect(); let package_form_spans: Vec> = parsed_files .iter() + .copied() .map(|(file, view)| { let mut spans = Vec::new(); collect_package_form_spans(file.dialect, view, &mut spans); @@ -60,6 +50,7 @@ pub fn collect_unused_definition_candidates( .collect(); let atom_needles: Vec> = parsed_files .iter() + .copied() .map(|(_, view)| { let mut needles = std::collections::HashSet::new(); collect_reference_needles(view, &mut needles); @@ -117,7 +108,7 @@ pub fn collect_unused_definition_candidates( fn file_unused_definition_candidates( files: &[RemoveUnusedDefinitionInputFile], - parsed_files: &[(&RemoveUnusedDefinitionInputFile, ExpressionView)], + parsed_files: &[(&RemoveUnusedDefinitionInputFile, &ExpressionView)], package_form_spans: &[Vec], atom_needles: &[std::collections::HashSet], file_index: usize, @@ -150,7 +141,7 @@ fn file_unused_definition_candidates( .iter() .enumerate() .flat_map(|(other_index, other)| { - let (_, other_view) = &parsed_files[other_index]; + let (_, other_view) = parsed_files[other_index]; let mut spans = Vec::new(); if atom_needles[other_index].contains(&needle) { collect_symbol_references( diff --git a/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/mod.rs b/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/mod.rs index 54bd4e7b0..11a351cb4 100644 --- a/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/mod.rs +++ b/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/mod.rs @@ -44,6 +44,7 @@ fn file_with_dialect( definitions, atoms: tree.atom_occurrences(), text: text.to_owned(), + root_view: tree.root_view(), } } diff --git a/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/validation.rs b/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/validation.rs index 734ae3c1d..fa9399a17 100644 --- a/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/validation.rs +++ b/packages/feature/remove-unused/src/remove_unused_definition/domain/tests/validation.rs @@ -6,28 +6,14 @@ use paredit_core_syntax::sexpr::ByteSpan; use paredit_core_syntax::sexpr::SyntaxTree; use std::path::PathBuf; -#[test] -fn rejects_unparseable_input_files_instead_of_panicking() { - let request = RemoveUnusedDefinitionsRequest { - files: vec![RemoveUnusedDefinitionInputFile { - path: PathBuf::from("broken.lisp"), - dialect: Dialect::CommonLisp, - package: Some("app".to_owned()), - definitions: Vec::new(), - atoms: Vec::new(), - text: "(defun broken ()".to_owned(), - }], - package_definitions: Vec::new(), - include_protected: false, - include_exported: false, - }; - - let error = plan_remove_unused_definitions(request).expect_err("invalid input must fail"); - - assert!( - error.to_string().contains("failed to parse broken.lisp"), - "unexpected error: {error:#}" - ); +/// A placeholder root view for a fixture whose own text is deliberately +/// unparseable: the dialect check this test exercises rejects the file +/// before any view is ever read, so what is stored here is never examined, +/// and it need not correspond to `text`. +fn placeholder_root_view() -> paredit_core_syntax::sexpr::ExpressionView { + SyntaxTree::parse_with_dialect("()", Dialect::CommonLisp) + .expect("placeholder must parse") + .root_view() } #[test] @@ -41,6 +27,7 @@ fn rejects_unknown_dialect_before_parsing_any_file() { definitions: Vec::new(), atoms: Vec::new(), text: "(defun broken ()".to_owned(), + root_view: placeholder_root_view(), }, RemoveUnusedDefinitionInputFile { path: PathBuf::from("unknown.lisp"), @@ -49,6 +36,7 @@ fn rejects_unknown_dialect_before_parsing_any_file() { definitions: Vec::new(), atoms: Vec::new(), text: "()".to_owned(), + root_view: placeholder_root_view(), }, ], package_definitions: Vec::new(), @@ -86,6 +74,9 @@ fn rejects_invalid_definition_symbols_instead_of_panicking() { .expect("fixture must parse") .atom_occurrences(), text: text.to_owned(), + root_view: SyntaxTree::parse_with_dialect(text, Dialect::CommonLisp) + .expect("fixture must parse") + .root_view(), }], package_definitions: Vec::new(), include_protected: false, diff --git a/packages/feature/remove-unused/src/remove_unused_definition/domain/types.rs b/packages/feature/remove-unused/src/remove_unused_definition/domain/types.rs index b981a8f13..a9fb9129f 100644 --- a/packages/feature/remove-unused/src/remove_unused_definition/domain/types.rs +++ b/packages/feature/remove-unused/src/remove_unused_definition/domain/types.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use paredit_core_syntax::definition::DefinitionCategory; use paredit_core_syntax::dialect::Dialect; -use paredit_core_syntax::sexpr::{AtomOccurrence, ByteSpan}; +use paredit_core_syntax::sexpr::{AtomOccurrence, ByteSpan, ExpressionView}; use paredit_feature_package::package_report::domain::PackageDefinitionReport; #[derive(Debug, Clone)] @@ -13,6 +13,13 @@ pub struct RemoveUnusedDefinitionInputFile { pub definitions: Vec, pub atoms: Vec, pub text: String, + /// The root view from the parse this file was already loaded with. + /// + /// Kept alongside `text` rather than instead of it: `text` is still read + /// directly for substring reference-needle scans, but this is what saves + /// `collect_unused_definition_candidates` from re-parsing `text` from + /// scratch just to get a view it already had once. + pub root_view: ExpressionView, } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/packages/feature/rename/src/rename/domain/replace_call/call_site.rs b/packages/feature/rename/src/rename/domain/replace_call/call_site.rs index 16e3f3cc0..40a9c5892 100644 --- a/packages/feature/rename/src/rename/domain/replace_call/call_site.rs +++ b/packages/feature/rename/src/rename/domain/replace_call/call_site.rs @@ -10,7 +10,7 @@ pub fn replace_call_site_from_view( view: &ExpressionView, dialect: Dialect, input: &str, - path: String, + path: impl FnOnce() -> String, from: &SymbolName, to: &SymbolName, ) -> Option { @@ -23,7 +23,7 @@ pub fn replace_call_site_from_view( let head_span = view.children.first().map(|child| child.span)?; Some(ReplaceFunctionCallSite { - path, + path: path(), head_span, span: view.span, replacement: to.as_str().to_owned(), diff --git a/packages/feature/rename/src/rename/domain/replace_call/collect.rs b/packages/feature/rename/src/rename/domain/replace_call/collect.rs index 4f11f9b4d..076411f68 100644 --- a/packages/feature/rename/src/rename/domain/replace_call/collect.rs +++ b/packages/feature/rename/src/rename/domain/replace_call/collect.rs @@ -65,11 +65,12 @@ pub fn collect_explicit_replace_call_sites( } .into()); } - let site = replace_call_site_from_view(&view, dialect, input, path.to_string(), from, to) - .ok_or_else(|| CallSiteError::NotACall { - path: path.to_string(), - function: from.to_string(), - })?; + let site = + replace_call_site_from_view(&view, dialect, input, || path.to_string(), from, to) + .ok_or_else(|| CallSiteError::NotACall { + path: path.to_string(), + function: from.to_string(), + })?; calls.push(site); } calls.sort_by_key(|site| site.head_span.start()); @@ -135,7 +136,7 @@ fn collect_replace_call_sites_from_view( view, ctx.dialect, ctx.input, - path.to_string(), + || path.to_string(), ctx.from, ctx.to, ) { diff --git a/packages/feature/rename/src/rename/domain/wrap/call_site.rs b/packages/feature/rename/src/rename/domain/wrap/call_site.rs index 02b16605b..d70323789 100644 --- a/packages/feature/rename/src/rename/domain/wrap/call_site.rs +++ b/packages/feature/rename/src/rename/domain/wrap/call_site.rs @@ -9,7 +9,7 @@ pub fn wrap_call_site_from_view( view: &ExpressionView, dialect: Dialect, input: &str, - path: String, + path: impl FnOnce() -> String, function: &SymbolName, wrapper: &SymbolName, template: Option<&WrapFunctionCallTemplate>, @@ -24,7 +24,7 @@ pub fn wrap_call_site_from_view( None => format!("({} {})", wrapper.as_str(), text), }; Some(WrapFunctionCallSite { - path, + path: path(), span: view.content_span, replacement, text, diff --git a/packages/feature/rename/src/rename/domain/wrap/collect.rs b/packages/feature/rename/src/rename/domain/wrap/collect.rs index 3a293f26c..def66a202 100644 --- a/packages/feature/rename/src/rename/domain/wrap/collect.rs +++ b/packages/feature/rename/src/rename/domain/wrap/collect.rs @@ -88,7 +88,7 @@ pub fn collect_wrap_explicit_call_sites( &view, dialect, input, - path.to_string(), + || path.to_string(), function, wrapper, template, @@ -169,7 +169,7 @@ fn collect_wrap_call_sites_from_view( view, collection.dialect, collection.input, - path.to_string(), + || path.to_string(), collection.function, collection.wrapper, collection.template, diff --git a/packages/feature/semantic-report/src/constant_report/cli/workflow.rs b/packages/feature/semantic-report/src/constant_report/cli/workflow.rs index 66ce8271d..b958f5ff9 100644 --- a/packages/feature/semantic-report/src/constant_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/constant_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::constant_report::cli::args::ConstantReportArgs; use crate::constant_report::cli::render::print_constant_report; @@ -12,13 +14,18 @@ use crate::shared::SemanticFile; pub fn constant_report(args: ConstantReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_constant_report(&SemanticFile::analyze( - file, dialect, tree, - ))); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_constant_report(&SemanticFile::analyze( + file, + dialect, + tree.clone(), + ))) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_constant_report_policy( ConstantReportPolicyOptions::new(args.fail_on_foldable), diff --git a/packages/feature/semantic-report/src/effect_report/cli/workflow.rs b/packages/feature/semantic-report/src/effect_report/cli/workflow.rs index d52488156..e83349d5d 100644 --- a/packages/feature/semantic-report/src/effect_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/effect_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::effect_report::cli::args::EffectReportArgs; use crate::effect_report::cli::render::print_effect_report; @@ -12,13 +14,18 @@ use crate::shared::SemanticFile; pub fn effect_report(args: EffectReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_effect_report(&SemanticFile::analyze( - file, dialect, tree, - ))); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_effect_report(&SemanticFile::analyze( + file, + dialect, + tree.clone(), + ))) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_effect_policy(EffectPolicyOptions::new(args.fail_on_unknown), &reports); let passed = policy.passed; diff --git a/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs b/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs index 32c931cce..8101ed126 100644 --- a/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs +++ b/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs @@ -4,8 +4,8 @@ use serde_json::json; use paredit_core_cli::args::OutputFormat; use paredit_core_cli::color::{Painter, colorize_diff}; use paredit_core_cli::shared::{ - apply_byte_span_edits, expand_input_files, read_input_dialect_and_tree, unified_diff, - write_files_with_rollback, + analyze_files, apply_byte_span_edits, expand_input_files, note_partial_file_failures, + total_file_failure, unified_diff, write_files_with_rollback, }; use paredit_core_syntax::sexpr::ByteSpan; @@ -46,11 +46,9 @@ struct FoldPlan { /// `double-float`'s type. pub fn fold_constants(args: FoldConstantsArgs) -> CliResult<()> { let files = expand_input_files(&args.files, args.dialect)?; - let mut plans = Vec::with_capacity(files.len()); - for file in &files { - let (input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - let report = build_constant_report(&SemanticFile::analyze(file, dialect, tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { + let report = build_constant_report(&SemanticFile::analyze(file, dialect, tree.clone())); let mut edits: Vec<(ByteSpan, String)> = Vec::new(); let mut folds = Vec::new(); @@ -71,14 +69,19 @@ pub fn fold_constants(args: FoldConstantsArgs) -> CliResult<()> { } else { apply_byte_span_edits(&input.text, edits)? }; - plans.push(FoldPlan { + CliResult::Ok(FoldPlan { path: file.clone(), dialect, before: input.text.clone(), rewritten, folds, - }); + }) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let plans = analysis.succeeded; if args.diff { let painter = Painter::stdout(); diff --git a/packages/feature/semantic-report/src/magic_number_report/cli/workflow.rs b/packages/feature/semantic-report/src/magic_number_report/cli/workflow.rs index 31a3e99f0..85032b937 100644 --- a/packages/feature/semantic-report/src/magic_number_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/magic_number_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::magic_number_report::cli::args::MagicNumberReportArgs; use crate::magic_number_report::cli::render::print_magic_number_report; @@ -11,11 +13,14 @@ use crate::magic_number_report::usecase::{ pub fn magic_number_report(args: MagicNumberReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_magic_number_report(file, dialect, &tree)); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_magic_number_report(file, dialect, tree)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_fail_on_magic_number_policy(args.fail_on_magic_number, &reports); let passed = policy.passed; diff --git a/packages/feature/semantic-report/src/narrowing_report/cli/workflow.rs b/packages/feature/semantic-report/src/narrowing_report/cli/workflow.rs index 8aaabc92d..271f6c9c3 100644 --- a/packages/feature/semantic-report/src/narrowing_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/narrowing_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::narrowing_report::cli::args::NarrowingReportArgs; use crate::narrowing_report::cli::render::print_narrowing_report; @@ -12,13 +14,18 @@ use crate::shared::SemanticFile; pub fn narrowing_report(args: NarrowingReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_narrowing_report(&SemanticFile::analyze( - file, dialect, tree, - ))); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_narrowing_report(&SemanticFile::analyze( + file, + dialect, + tree.clone(), + ))) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_narrowing_policy(NarrowingPolicyOptions::new(args.fail_on_none), &reports); diff --git a/packages/feature/semantic-report/src/type_report/cli/workflow.rs b/packages/feature/semantic-report/src/type_report/cli/workflow.rs index cb34f3304..101438a7a 100644 --- a/packages/feature/semantic-report/src/type_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/type_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::shared::SemanticFile; use crate::type_report::cli::args::TypeReportArgs; @@ -12,13 +14,18 @@ use crate::type_report::usecase::{ pub fn type_report(args: TypeReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_type_report(&SemanticFile::analyze( - file, dialect, tree, - ))); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_type_report(&SemanticFile::analyze( + file, + dialect, + tree.clone(), + ))) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_type_report_policy( TypeReportPolicyOptions::new(args.fail_on_contradiction), diff --git a/packages/feature/semantic-report/src/value_propagation_report/cli/workflow.rs b/packages/feature/semantic-report/src/value_propagation_report/cli/workflow.rs index e3164b465..c4bdf21cb 100644 --- a/packages/feature/semantic-report/src/value_propagation_report/cli/workflow.rs +++ b/packages/feature/semantic-report/src/value_propagation_report/cli/workflow.rs @@ -1,6 +1,8 @@ -use paredit_core_cli::CommandResult; +use paredit_core_cli::{CliResult, CommandResult}; -use paredit_core_cli::shared::{expand_input_files, read_input_dialect_and_tree}; +use paredit_core_cli::shared::{ + analyze_files, expand_input_files, note_partial_file_failures, total_file_failure, +}; use crate::shared::SemanticFile; use crate::value_propagation_report::cli::args::ValuePropagationReportArgs; @@ -13,13 +15,18 @@ use crate::value_propagation_report::usecase::{ pub fn value_propagation_report(args: ValuePropagationReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; - let mut reports = Vec::with_capacity(files.len()); - for file in &files { - let (_, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), args.dialect)?; - reports.push(build_value_propagation_report(&SemanticFile::analyze( - file, dialect, tree, - ))); + let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { + CliResult::Ok(build_value_propagation_report(&SemanticFile::analyze( + file, + dialect, + tree.clone(), + ))) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); } + note_partial_file_failures(&analysis.failed); + let reports = analysis.succeeded; let policy = evaluate_value_propagation_policy( ValuePropagationPolicyOptions::new(args.min_coverage), diff --git a/packages/feature/similarity/src/duplicate_report/cli/workflow.rs b/packages/feature/similarity/src/duplicate_report/cli/workflow.rs index 3a6b2ba3d..eede97893 100644 --- a/packages/feature/similarity/src/duplicate_report/cli/workflow.rs +++ b/packages/feature/similarity/src/duplicate_report/cli/workflow.rs @@ -6,7 +6,9 @@ use crate::duplicate_report::usecase::{ collect_replacement_plan_batches, }; use paredit_core_cli::CliResult; -use paredit_core_cli::shared::read_input_dialect_and_tree; +use paredit_core_cli::shared::{ + analyze_files_raw, note_partial_file_failures, read_input_dialect_and_tree, total_file_failure, +}; pub fn duplicate_report(args: DuplicateReportArgs) -> CliResult<()> { ensure_thresholds(args.min_group_size, args.min_node_count)?; @@ -53,10 +55,25 @@ fn collect_duplicate_candidate_groups( min_node_count: usize, min_group_size: usize, ) -> CliResult { - let mut candidates = DuplicateCandidateAccumulator::new(min_node_count); - - for file in discover_duplicate_report_files(roots)? { + let files = discover_duplicate_report_files(roots)?; + // The read and parse of each file are independent, but `add_source` + // itself is not: it appends to a shared candidate map in call order, and + // that order becomes the order occurrences are reported within a + // duplicate group. Only the read+parse step runs in parallel; `finish`'s + // fold below stays a plain sequential loop over `analysis.succeeded`, + // which preserves input order regardless of which file's read finished + // first. + let analysis = analyze_files_raw(&files, |file| { let (_input, dialect, tree) = read_input_dialect_and_tree(Some(file.clone()), dialect)?; + CliResult::Ok((tree, file.clone(), dialect)) + }); + if analysis.is_total_failure() { + return Err(total_file_failure(analysis.failed).into()); + } + note_partial_file_failures(&analysis.failed); + + let mut candidates = DuplicateCandidateAccumulator::new(min_node_count); + for (tree, file, dialect) in analysis.succeeded { candidates.add_source(tree, file, dialect)?; } From dd1135138bc550feee58c894ac60fe75137332a1 Mon Sep 17 00:00:00 2001 From: takeokunn Date: Mon, 24 Aug 2026 15:56:37 +0900 Subject: [PATCH 2/4] perf(workspace): raise cache-validation parallel threshold to a confirmed-safe size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI's benchmark gate caught a real regression: cache-dir/warm/128 (8 directories, right at the old PARALLEL_VALIDATION_THRESHOLD of 8) was ~37% slower than the serial path, confirmed with a lower confidence bound of +36.5% — thread-spawn overhead dominating a handful of single-syscall stat checks. warm/1024 (64 directories) was genuinely ~28% faster, confirming the parallel path pays off at that scale. Raise the threshold to 64, the larger of the two confirmed points, rather than guess at the crossover between them. --- packages/core/workspace/src/workspace/cache.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core/workspace/src/workspace/cache.rs b/packages/core/workspace/src/workspace/cache.rs index 7d304a2b5..1e2d00dc2 100644 --- a/packages/core/workspace/src/workspace/cache.rs +++ b/packages/core/workspace/src/workspace/cache.rs @@ -384,7 +384,15 @@ fn read_entry(entry: &Value) -> Option { } /// Below this many entries, a thread costs more than the stats it would save. -const PARALLEL_VALIDATION_THRESHOLD: usize = 8; +/// +/// Each item here is one `fs::metadata` call, or for a directory one +/// `fs::read_dir(...).count()` — cheap enough that thread setup can dominate +/// the work it was meant to parallelize. `benches/cache_dir.rs`'s +/// `cache-dir/warm/128` arm (8 directories, the previous threshold) measured +/// threading at that count as ~37% *slower* than the serial path; `warm/1024` +/// (64 directories) measured a ~28% win. This constant sits at the larger, +/// confirmed-safe end rather than guessing at the crossover between them. +const PARALLEL_VALIDATION_THRESHOLD: usize = 64; fn directories_are_unchanged(entry: &Value) -> bool { let Some(directories) = entry["directories"].as_array() else { From 1d7c156eb1a1884e111e722c228065676d6130b7 Mon Sep 17 00:00:00 2001 From: takeokunn Date: Sun, 30 Aug 2026 01:19:39 +0900 Subject: [PATCH 3/4] chore: satisfy release verification gates --- fuzz/corpus/format_idempotence/basic.lisp | 3 +- .../format_idempotence/numeric-dispatch.lisp | 3 +- fuzz/corpus/parse/basic.lisp | 3 +- fuzz/corpus/parse/feature-expressions.lisp | 1 + fuzz/corpus/parse/numeric-dispatch.lisp | 3 +- packages/core/cli/src/args.rs | 2 +- packages/core/cli/src/color.rs | 4 +- packages/core/cli/src/diagnosis.rs | 2 +- packages/core/cli/src/diff.rs | 2 +- packages/core/cli/src/gate.rs | 2 +- packages/core/cli/src/io.rs | 10 +- packages/core/cli/src/pager.rs | 2 +- packages/core/cli/src/runtime.rs | 2 +- packages/core/cli/src/shared.rs | 2 +- packages/core/cli/src/terminal.rs | 2 +- packages/core/lint-engine/src/suppression.rs | 2 +- .../src/semantics/binding/service/mod.rs | 2 +- packages/core/syntax/src/emacs_lisp/mod.rs | 2 +- .../core/syntax/src/sexpr/formatter/core.rs | 4 +- .../src/sexpr/formatter/lists/definitions.rs | 4 +- .../core/syntax/src/sexpr/formatter/styles.rs | 20 +- packages/core/syntax/src/sexpr/quote_edit.rs | 2 +- .../core/syntax/src/sexpr/tests/formatter.rs | 9 + packages/core/syntax/src/sexpr/tree.rs | 2 +- packages/core/workspace/src/workspace/glob.rs | 2 +- .../core/workspace/src/workspace/ignore.rs | 2 +- .../emacs-lisp/src/obsolete_cl_alias/rule.rs | 2 +- .../src/generate_defsystem/cli/args.rs | 4 +- .../src/asdf_system_missing_version/domain.rs | 2 +- .../src/defpackage_without_in_package/rule.rs | 4 +- .../feature/lint-build-system/src/support.rs | 2 +- .../feature/lint-call-shape/src/support.rs | 2 +- .../feature/lint-carp-idiom/src/support.rs | 4 +- .../feature/lint-clojure-depth/src/support.rs | 4 +- .../feature/lint-clojure-idiom/src/lib.rs | 12 +- .../feature/lint-clojure-idiom/src/support.rs | 6 +- .../src/eval_when_execute_only/domain.rs | 2 +- .../feature/lint-compile-time/src/support.rs | 4 +- .../feature/lint-concurrency/src/support.rs | 2 +- .../lint-condition-depth/src/support.rs | 4 +- .../domain.rs | 4 +- .../lint-condition-system/src/support.rs | 2 +- .../feature/lint-conditional/src/support.rs | 2 +- .../src/clojure_pre_post_vacuous/domain.rs | 2 +- .../lint-contract-annotation/src/support.rs | 2 +- .../src/typed_racket_arity_mismatch/domain.rs | 2 +- .../src/malformed_iteration_spec/cli/args.rs | 7 +- .../feature/lint-control-flow/src/support.rs | 2 +- packages/feature/lint-custom/src/pattern.rs | 4 +- .../lint-data-structure/src/support.rs | 2 +- .../discarded_destructive_sequence_result.rs | 2 +- .../lint-destructive-sequence/src/support.rs | 2 +- .../feature/lint-documentation/src/support.rs | 6 +- .../src/todo_fixme_no_attribution/domain.rs | 2 +- .../repeating_timer_handle_discarded/rule.rs | 2 +- .../src/fennel_bad_unpack/domain.rs | 2 +- .../src/defpackage_quoted/domain.rs | 2 +- .../src/redundant_quote/domain.rs | 2 +- .../domain.rs | 2 +- packages/feature/lint-hy-depth/src/support.rs | 2 +- .../feature/lint-hy-depth/tests/corpus.rs | 20 +- .../lint-hy-depth/tests/fixtures/clean.hy | 113 +- .../lint-hy-depth/tests/fixtures/dangerous.hy | 94 +- .../feature/lint-introspection/src/support.rs | 2 +- .../lint-iteration-flow/src/loop_syntax.rs | 6 +- .../src/illegal_guard_call/domain.rs | 2 +- .../lint-macro-authoring/src/support.rs | 4 +- packages/feature/lint-numeric/src/support.rs | 6 +- .../lint-numeric/src/t_comparison/domain.rs | 2 +- .../src/method_qualifier_typo/domain.rs | 2 +- .../feature/lint-object-system/src/support.rs | 2 +- .../lint-package-hygiene/src/support.rs | 2 +- .../src/linear_search_in_loop.rs | 2 +- .../repeated_hash_table_lookup_same_key.rs | 2 +- .../src/char_code_limit_loop.rs | 4 +- .../feature/lint-portability/src/support.rs | 2 +- .../feature/lint-racket-depth/src/support.rs | 2 +- .../tests/fixtures/clean.rkt | 112 +- .../tests/fixtures/dangerous.rkt | 12 +- .../src/commented_repl_transcript/domain.rs | 2 +- .../src/leftover_format_debug_marker/rule.rs | 2 +- .../src/leftover_inspect_call/rule.rs | 2 +- .../src/leftover_print_debug/domain.rs | 2 +- .../src/leftover_print_debug/rule.rs | 2 +- .../src/leftover_trace_call/rule.rs | 2 +- .../feature/lint-repl-debug/src/support.rs | 20 +- .../src/declarative_style_score.rs | 2 +- packages/feature/lint-safety/src/support.rs | 2 +- .../feature/lint-scheme-idiom/src/support.rs | 2 +- .../tests/fixtures/clean.rkt | 69 +- .../tests/fixtures/clean.scm | 111 +- .../tests/fixtures/dangerous.rkt | 18 +- .../tests/fixtures/dangerous.scm | 18 +- .../domain.rs | 2 +- .../redundant_into_empty_collection/domain.rs | 2 +- packages/feature/lint-sequence/src/support.rs | 4 +- .../feature/lint-string-char/src/support.rs | 2 +- packages/feature/lint-testing/src/support.rs | 2 +- .../lint-type-declaration/src/support.rs | 4 +- .../src/duplicate_method_report/domain.rs | 2 +- .../src/macro_hygiene_report/rule/mod.rs | 2 +- packages/feature/schema-check/src/dsl.rs | 2 +- .../src/effect_report/domain/mod.rs | 4 +- src/lint/mod.rs | 2 +- tests/cli/analysis_report.rs | 2 +- tests/fixtures/corpus/carp.carp | 89 +- tests/fixtures/corpus/clojure.clj | 28 +- tests/fixtures/corpus/clos.lisp | 31 +- tests/fixtures/corpus/deep-nesting.lisp | 27 +- tests/fixtures/corpus/elisp.el | 32 +- tests/fixtures/corpus/fennel.fnl | 89 +- tests/fixtures/corpus/hy.hy | 107 +- tests/fixtures/corpus/janet.janet | 97 +- tests/fixtures/corpus/lfe.lfe | 57 +- tests/fixtures/corpus/racket.rkt | 86 +- tests/fixtures/corpus/reader-syntax.lisp | 64 +- tests/fixtures/corpus/scheme.scm | 1 - tests/fixtures/lint_golden/broad.lisp | 504 +++++-- tests/fixtures/lint_golden/emacs-lisp.el | 12 +- .../expected/broad.fixed.source.golden | 478 +++++-- .../expected/broad.fixplan.json.golden | 576 ++++---- .../lint_golden/expected/broad.json.golden | 570 ++++---- .../lint_golden/expected/broad.sarif.golden | 1196 ++++++++--------- .../lint_golden/expected/broad.text.golden | 284 ++-- .../expected/emacs-lisp.fixed.source.golden | 12 +- .../expected/emacs-lisp.fixplan.json.golden | 10 +- .../expected/emacs-lisp.json.golden | 24 +- .../expected/emacs-lisp.sarif.golden | 50 +- .../expected/emacs-lisp.text.golden | 14 +- .../expected/nested.fixed.source.golden | 4 +- .../expected/nested.fixplan.json.golden | 132 +- .../lint_golden/expected/nested.json.golden | 76 +- .../lint_golden/expected/nested.sarif.golden | 152 +-- .../lint_golden/expected/nested.text.golden | 38 +- .../expected/suppressed.fixed.source.golden | 3 +- .../expected/suppressed.fixplan.json.golden | 6 +- .../expected/suppressed.json.golden | 6 +- .../expected/suppressed.sarif.golden | 8 +- .../expected/suppressed.text.golden | 2 +- tests/fixtures/lint_golden/nested.lisp | 15 +- tests/fixtures/lint_golden/suppressed.lisp | 3 +- tests/fixtures/sample.el | 3 +- .../semantic_coverage_corpus/geometry.lisp | 3 +- .../semantic_coverage_corpus/utilities.lisp | 3 +- 144 files changed, 3128 insertions(+), 2640 deletions(-) diff --git a/fuzz/corpus/format_idempotence/basic.lisp b/fuzz/corpus/format_idempotence/basic.lisp index cbc902aa3..de72b003f 100644 --- a/fuzz/corpus/format_idempotence/basic.lisp +++ b/fuzz/corpus/format_idempotence/basic.lisp @@ -1 +1,2 @@ -(defun f (x) (+ x 1)) +(defun f (x) + (+ x 1)) diff --git a/fuzz/corpus/format_idempotence/numeric-dispatch.lisp b/fuzz/corpus/format_idempotence/numeric-dispatch.lisp index 953f91e04..a63562c9c 100644 --- a/fuzz/corpus/format_idempotence/numeric-dispatch.lisp +++ b/fuzz/corpus/format_idempotence/numeric-dispatch.lisp @@ -1 +1,2 @@ -(defparameter *z* (list #C(0.0 1.0) #2A((1 2) (3 4)) #S(p :x 1))) +(defparameter *z* + (list #C(0.0 1.0) #2A((1 2) (3 4)) #S(p :x 1))) diff --git a/fuzz/corpus/parse/basic.lisp b/fuzz/corpus/parse/basic.lisp index cbc902aa3..de72b003f 100644 --- a/fuzz/corpus/parse/basic.lisp +++ b/fuzz/corpus/parse/basic.lisp @@ -1 +1,2 @@ -(defun f (x) (+ x 1)) +(defun f (x) + (+ x 1)) diff --git a/fuzz/corpus/parse/feature-expressions.lisp b/fuzz/corpus/parse/feature-expressions.lisp index 4405aa72d..4a04f64e4 100644 --- a/fuzz/corpus/parse/feature-expressions.lisp +++ b/fuzz/corpus/parse/feature-expressions.lisp @@ -1,2 +1,3 @@ #+(and sbcl (not win32)) (defun x () t) + #-sbcl (defun x () nil) diff --git a/fuzz/corpus/parse/numeric-dispatch.lisp b/fuzz/corpus/parse/numeric-dispatch.lisp index 953f91e04..a63562c9c 100644 --- a/fuzz/corpus/parse/numeric-dispatch.lisp +++ b/fuzz/corpus/parse/numeric-dispatch.lisp @@ -1 +1,2 @@ -(defparameter *z* (list #C(0.0 1.0) #2A((1 2) (3 4)) #S(p :x 1))) +(defparameter *z* + (list #C(0.0 1.0) #2A((1 2) (3 4)) #S(p :x 1))) diff --git a/packages/core/cli/src/args.rs b/packages/core/cli/src/args.rs index 8efb99c31..55505973a 100644 --- a/packages/core/cli/src/args.rs +++ b/packages/core/cli/src/args.rs @@ -230,7 +230,7 @@ pub struct SelectorArgs { /// Select the smallest expression containing byte offset. #[arg(long, group = "selector-base")] pub at: Option, - /// Select the smallest expression at LINE[:COLUMN], both 1-based. + /// Select the smallest expression at `LINE[:COLUMN]`, both 1-based. #[arg(long, value_name = "LINE[:COLUMN]", group = "selector-base")] pub line_column: Option, /// Select the definition named SYMBOL. diff --git a/packages/core/cli/src/color.rs b/packages/core/cli/src/color.rs index ed383266f..8fb039427 100644 --- a/packages/core/cli/src/color.rs +++ b/packages/core/cli/src/color.rs @@ -125,7 +125,7 @@ fn stdout_is_terminal() -> bool { *STDOUT_IS_TERMINAL.get_or_init(|| std::io::stdout().is_terminal()) } -/// Forces [`stdout_is_terminal`]'s cache to resolve now, before something +/// Forces `stdout_is_terminal`'s cache to resolve now, before something /// else changes what fd 1 points at. A no-op once the cache already holds a /// value, which is exactly the "first check wins" contract callers need. pub fn prime_stdout_terminal_cache() { @@ -201,7 +201,7 @@ impl Painter { } } -/// Colorizes a [`crate::diff::unified_diff`] result for a terminal: green +/// Colorizes a `crate::diff::unified_diff` result for a terminal: green /// `+` lines, red `-` lines, cyan hunk headers, bold file headers. /// /// Takes the finished diff text rather than folding into `unified_diff` diff --git a/packages/core/cli/src/diagnosis.rs b/packages/core/cli/src/diagnosis.rs index a13238759..6c32fbc50 100644 --- a/packages/core/cli/src/diagnosis.rs +++ b/packages/core/cli/src/diagnosis.rs @@ -495,7 +495,7 @@ pub struct Diagnosis { /// The byte position the failure names, when it names one. /// /// Populated from whichever typed variant already carries a position — - /// [`ParseError`] always does, a handful of [`StructureError`] and + /// `ParseError` always does, a handful of [`StructureError`] and /// [`SelectionError`] variants do — rather than by adding a span to every /// variant. A caller holding the source text can render a caret under it; /// [`render_caret`] does exactly that for the CLI's own stderr output. diff --git a/packages/core/cli/src/diff.rs b/packages/core/cli/src/diff.rs index e1eb76c57..6fb29b744 100644 --- a/packages/core/cli/src/diff.rs +++ b/packages/core/cli/src/diff.rs @@ -48,7 +48,7 @@ pub struct DiffStat { /// Counts hunks and changed lines in a string [`unified_diff`] produced. /// -/// Parses the rendered text rather than the internal [`DiffOp`] sequence: +/// Parses the rendered text rather than the internal `DiffOp` sequence: /// `unified_diff` already has an "omitted, too large" fallback whose shape /// this must agree with too, and re-deriving these counts from the same /// text a caller can also print keeps the two forms of output from ever diff --git a/packages/core/cli/src/gate.rs b/packages/core/cli/src/gate.rs index 082801a89..a3d17516c 100644 --- a/packages/core/cli/src/gate.rs +++ b/packages/core/cli/src/gate.rs @@ -30,7 +30,7 @@ pub struct GateFailure(pub String); /// Builds a gate failure, ready to return from a command entry point. /// -/// Returns [`CommandFailure`] rather than [`GateFailure`] so that the ~30 +/// Returns `CommandFailure` rather than [`GateFailure`] so that the ~30 /// existing `return Err(gate_failure(format!(...)))` sites keep compiling /// unchanged: `Err(...)` performs no conversion of its own, only `?` does. The /// bare variant is still reachable as `CommandFailure::Gate` for a caller that diff --git a/packages/core/cli/src/io.rs b/packages/core/cli/src/io.rs index a352e0aad..a29cf36ba 100644 --- a/packages/core/cli/src/io.rs +++ b/packages/core/cli/src/io.rs @@ -28,7 +28,7 @@ const CLEANUP_QUARANTINE_MODE: u32 = 0o700; /// /// Still the default and no longer the only possible value: a run may lower it /// with `--max-input-bytes` or `PAREDIT_MAX_INPUT_BYTES`, which is what -/// [`max_source_input_bytes`] resolves. Kept public and unchanged because it +/// `max_source_input_bytes` resolves. Kept public and unchanged because it /// is the documented default and several callers quote it as such. pub const MAX_SOURCE_INPUT_BYTES: u64 = paredit_core_safety::limits::DEFAULT_MAX_INPUT_BYTES; @@ -1199,17 +1199,17 @@ pub struct WritabilityCheck { /// Checks whether `path` could be written to right now, changing nothing. /// /// Reuses the exact staging step a real write goes through — the same -/// batch-level refusals ([`ensure_writes_are_permitted`]), the same +/// batch-level refusals (`ensure_writes_are_permitted`), the same /// symlink/regular-file refusals, the same parent-directory permission -/// check, the same write lock (see [`acquire_write_lock`]), and, because +/// check, the same write lock (see `acquire_write_lock`), and, because /// staging writes a same-size placeholder into a sibling file on the same /// filesystem before ever touching `path` itself, the same evidence of /// whether there is room for a write of about this size — then discards the /// staged sibling it created instead of publishing it. /// /// The backup copy is the one staging step this deliberately skips, via -/// [`StagingIntent::Probe`]: it exists only to roll a publish back, and a -/// probe never publishes. See [`StagingIntent`] for what it used to cost. +/// `StagingIntent::Probe`: it exists only to roll a publish back, and a +/// probe never publishes. See `StagingIntent` for what it used to cost. /// /// `--dry-run` is checked *first*, before any lock or sibling file. The /// guarantee that flag makes — nothing is written to disk — has to hold for diff --git a/packages/core/cli/src/pager.rs b/packages/core/cli/src/pager.rs index 34d52bc49..6f9c96902 100644 --- a/packages/core/cli/src/pager.rs +++ b/packages/core/cli/src/pager.rs @@ -10,7 +10,7 @@ //! `println!` — lands in the pager without knowing it exists. //! //! Unix-only, like the rest of this crate's raw-fd and xattr code -//! ([`crate::shared::io`]'s macOS ACL preservation is the other example): +//! (`crate::shared::io`'s macOS ACL preservation is the other example): //! `dup2` and `/bin/sh` are POSIX, and there is no Windows pager convention //! to fall back to. `--paginate` is simply inert there. //! diff --git a/packages/core/cli/src/runtime.rs b/packages/core/cli/src/runtime.rs index 08c766796..2ee6acbe7 100644 --- a/packages/core/cli/src/runtime.rs +++ b/packages/core/cli/src/runtime.rs @@ -148,7 +148,7 @@ pub struct RuntimeSettings { /// `None` keeps the existing strict-UTF-8 read path. Read-only commands /// work normally against a legacy (Shift_JIS, EUC-JP, ISO-8859-1, ...) /// source file once this is set; a write is refused instead of silently - /// re-encoding the file to UTF-8 — see [`writes_are_supported`]. + /// re-encoding the file to UTF-8 — see `writes_are_supported`. pub source_encoding: Option<&'static encoding_rs::Encoding>, } diff --git a/packages/core/cli/src/shared.rs b/packages/core/cli/src/shared.rs index bec510f4d..067616952 100644 --- a/packages/core/cli/src/shared.rs +++ b/packages/core/cli/src/shared.rs @@ -756,7 +756,7 @@ pub fn note_partial_file_failures(failures: &[FileFailure]) { /// /// - **Order is preserved.** Results come back in input order regardless of /// which thread finished first, so the report's bytes do not depend on -/// scheduling. Since [`claim_order_by_descending_size`] means the workers do +/// scheduling. Since `claim_order_by_descending_size` means the workers do /// not even *start* the files in input order, that is now an explicit /// reassembly rather than a happy accident of the partitioning: each result /// travels back paired with the index of the file it came from and is placed diff --git a/packages/core/cli/src/terminal.rs b/packages/core/cli/src/terminal.rs index 33b57458b..2fa6cd07b 100644 --- a/packages/core/cli/src/terminal.rs +++ b/packages/core/cli/src/terminal.rs @@ -15,7 +15,7 @@ const FALLBACK_WIDTH: usize = 80; /// The terminal's column count for stdout, or a fallback in this order: /// an ioctl reading (the terminal's actual width), then `COLUMNS` (what a /// shell exports, and what a wrapper without a real tty can still set), then -/// [`FALLBACK_WIDTH`]. +/// `FALLBACK_WIDTH`. #[must_use] pub fn width() -> usize { ioctl_width().or_else(columns_env).unwrap_or(FALLBACK_WIDTH) diff --git a/packages/core/lint-engine/src/suppression.rs b/packages/core/lint-engine/src/suppression.rs index c35f2763c..60e245b4d 100644 --- a/packages/core/lint-engine/src/suppression.rs +++ b/packages/core/lint-engine/src/suppression.rs @@ -1,5 +1,5 @@ //! Inline lint-suppression directives: source comments that silence -//! [`crate::domain::lint_report`] findings, the way `eslint-disable-next-line` +//! `crate::domain::lint_report` findings, the way `eslint-disable-next-line` //! or `# noqa` do elsewhere. //! //! A directive is any Lisp comment containing one of three tokens: diff --git a/packages/core/semantics/src/semantics/binding/service/mod.rs b/packages/core/semantics/src/semantics/binding/service/mod.rs index cc8f01a3c..6579bbe88 100644 --- a/packages/core/semantics/src/semantics/binding/service/mod.rs +++ b/packages/core/semantics/src/semantics/binding/service/mod.rs @@ -11,7 +11,7 @@ //! //! Four dialects share the walk. Everything above the binder dispatch — scope //! stack, reference resolution, opacity, quasiquote depth — is written once; -//! [`binders`], [`emacs_lisp`] and [`scheme`] differ only in which shape each +//! `binders`, `emacs_lisp` and `scheme` differ only in which shape each //! head has. mod assignments; diff --git a/packages/core/syntax/src/emacs_lisp/mod.rs b/packages/core/syntax/src/emacs_lisp/mod.rs index 5f67dbdb5..0e5cc1893 100644 --- a/packages/core/syntax/src/emacs_lisp/mod.rs +++ b/packages/core/syntax/src/emacs_lisp/mod.rs @@ -11,7 +11,7 @@ //! name. Routing Emacs Lisp through the Common Lisp head normalizer folded //! both distinctions away. //! * Whether a `let` binds lexically is decided by a *comment on line 1*, not -//! by the form. See [`header`]. +//! by the form. See `header`. //! * The `cl-lib` and `subr-x` families spell familiar shapes differently //! (`cl-flet`, `if-let*`, `pcase-let*`, `seq-let`) and add ones Common Lisp //! has no counterpart for. diff --git a/packages/core/syntax/src/sexpr/formatter/core.rs b/packages/core/syntax/src/sexpr/formatter/core.rs index 108a96d54..b9d61da32 100644 --- a/packages/core/syntax/src/sexpr/formatter/core.rs +++ b/packages/core/syntax/src/sexpr/formatter/core.rs @@ -245,7 +245,7 @@ impl Formatter { } /// Overrides the inline-width budget [`Formatter::with_dialect`] set to - /// [`MAX_INLINE_WIDTH`]. + /// `MAX_INLINE_WIDTH`. /// /// Re-clamps `indent` to the new width: an indent wider than the line /// budget could never fit an inline form regardless, and every existing @@ -272,7 +272,7 @@ impl Formatter { /// compiled-in single space. /// /// `0` means auto: each contiguous run of adjacent, trailing-commented - /// top-level forms (see [`Self::trailing_comment_columns`] for exactly + /// top-level forms (see `Self::trailing_comment_columns` for exactly /// what breaks a run) aligns to one column past its own widest form, /// independently of every other run. Any other value is a fixed column /// every trailing comment in the document aligns to, run or no run — a diff --git a/packages/core/syntax/src/sexpr/formatter/lists/definitions.rs b/packages/core/syntax/src/sexpr/formatter/lists/definitions.rs index 82b1578ae..6d6c410b1 100644 --- a/packages/core/syntax/src/sexpr/formatter/lists/definitions.rs +++ b/packages/core/syntax/src/sexpr/formatter/lists/definitions.rs @@ -192,9 +192,9 @@ impl Formatter { // The distinguished argument: stays on the head line // when it fits, breaks to distinguished_column (+4) when // it does not. - output.push(' '); - let col = Self::last_line_width(output); + let col = Self::last_line_width(output).saturating_add(1); if let Some(inline) = self.compact_node(tree, *child, col) { + output.push(' '); output.push_str(&inline); } else { Self::break_to_column(distinguished_column, output); diff --git a/packages/core/syntax/src/sexpr/formatter/styles.rs b/packages/core/syntax/src/sexpr/formatter/styles.rs index 286a730da..2dbb6aa15 100644 --- a/packages/core/syntax/src/sexpr/formatter/styles.rs +++ b/packages/core/syntax/src/sexpr/formatter/styles.rs @@ -55,32 +55,32 @@ pub(super) enum ListStyle { /// and `format.width-profiles` (see [`Formatter::with_indent_overrides`] and /// [`Formatter::with_width_profiles`]). /// -/// Deliberately narrower than [`ListStyle`]: every entry here has a single, +/// Deliberately narrower than `ListStyle`: every entry here has a single, /// generic, dialect-independent behavior a plain string can name without /// ambiguity. Left out, each for its own reason: /// /// - Every `Clojure*` variant — dialect-specific, and three of them /// (`ClojureThreading`, `ClojurePrefixBody`, `ClojurePairClauses`) carry an /// internal `usize` a bare style name has nowhere to put. -/// - [`ListStyle::SystemDefinition`] — the ASDF `defsystem` keyword/value +/// - `ListStyle::SystemDefinition` — the ASDF `defsystem` keyword/value /// plist header is narrow and Common-Lisp-specific enough that retargeting /// an unrelated symbol onto it would almost certainly be a mistake, not an /// intentional override. -/// - [`ListStyle::Defmethod`] — CLOS method syntax has an optional qualifier -/// before the lambda list that plain [`ListStyle::Definition`] does not; +/// - `ListStyle::Defmethod` — CLOS method syntax has an optional qualifier +/// before the lambda list that plain `ListStyle::Definition` does not; /// an arbitrary symbol given this style would have that slot misread. -/// - [`ListStyle::NamedLambda`] — renders identically to -/// [`ListStyle::TwoArgumentBody`]/[`ListStyle::If`] (all three call +/// - `ListStyle::NamedLambda` — renders identically to +/// `ListStyle::TwoArgumentBody`/`ListStyle::If` (all three call /// `format_prefix_body` with the same prefix length); a second name for /// the same behavior is a synonym, not a capability worth the surface area. -/// - [`ListStyle::LocalFunctions`] — the `flet`/`labels` nested +/// - `ListStyle::LocalFunctions` — the `flet`/`labels` nested /// binding-list-of-lists shape is specific to that pair of operators. -/// - [`ListStyle::ClauseForm`], [`ListStyle::Do`], [`ListStyle::Prog`] — +/// - `ListStyle::ClauseForm`, `ListStyle::Do`, `ListStyle::Prog` — /// `do`/`prog`'s bindings/end-test/body shape is a fixed positional /// structure, not a generic "body" a `defun`-like symbol would want. -/// - [`ListStyle::Declaration`], [`ListStyle::PairAssignment`] — +/// - `ListStyle::Declaration`, `ListStyle::PairAssignment` — /// `declare`/`setq`'s pairing shape is specific to those forms. -/// - [`ListStyle::Loop`] — has its own internal loop-keyword clause grammar, +/// - `ListStyle::Loop` — has its own internal loop-keyword clause grammar, /// unrelated to every other style here. pub const STYLE_NAMES: &[&str] = &[ "general", diff --git a/packages/core/syntax/src/sexpr/quote_edit.rs b/packages/core/syntax/src/sexpr/quote_edit.rs index a5f4a9db9..a0a5e4831 100644 --- a/packages/core/syntax/src/sexpr/quote_edit.rs +++ b/packages/core/syntax/src/sexpr/quote_edit.rs @@ -100,7 +100,7 @@ impl Edit { /// A form that is not a quote at all *is* refused, because that is a /// selector that missed rather than a no-op worth reporting as success. /// - /// `dialect` decides which operators count: see [`quote_operators`]. + /// `dialect` decides which operators count: see `quote_operators`. pub fn normalize_quotes( input: &str, tree: &SyntaxTree, diff --git a/packages/core/syntax/src/sexpr/tests/formatter.rs b/packages/core/syntax/src/sexpr/tests/formatter.rs index 06d973931..36bb3ad5f 100644 --- a/packages/core/syntax/src/sexpr/tests/formatter.rs +++ b/packages/core/syntax/src/sexpr/tests/formatter.rs @@ -240,6 +240,15 @@ fn formats_common_lisp_prefix_body_forms() { ); } +#[test] +fn prefix_body_break_does_not_leave_trailing_whitespace() { + let input = "(unwind-protect (restart-case (perform-a-very-long-operation) (retry () (perform-a-very-long-operation))) (cleanup))"; + let tree = SyntaxTree::parse(input).expect("valid"); + let formatted = Formatter::new(2).with_max_width(40).format(&tree); + + assert!(formatted.lines().all(|line| line.trim_end() == line)); +} + #[test] fn formats_common_lisp_with_body_macros() { let input = "(with-input-from-string (stream text) (read stream) (finish stream))\n(with-output-to-string (stream) (write value :stream stream) (finish-output stream))\n(with-hash-table-iterator (next table) (multiple-value-bind (more key value) (next) (when more (collect key value))))\n(with-package-iterator (next package :internal :external) (multiple-value-bind (more symbol status package) (next) (when more (collect symbol status package))))"; diff --git a/packages/core/syntax/src/sexpr/tree.rs b/packages/core/syntax/src/sexpr/tree.rs index 63985e314..1d175143a 100644 --- a/packages/core/syntax/src/sexpr/tree.rs +++ b/packages/core/syntax/src/sexpr/tree.rs @@ -598,7 +598,7 @@ impl SyntaxTree { /// zero with `(` — the shape essentially every top-level form in /// formatted Lisp source has — and re-parsing from there, so every /// problem in the document is visible in one pass. Bounded at - /// [`MAX_RECOVERED_ERRORS`] so a pathological input (a syntax error on + /// `MAX_RECOVERED_ERRORS` so a pathological input (a syntax error on /// every line) does a bounded amount of work and produces a bounded /// report rather than one entry per line of a huge file. /// diff --git a/packages/core/workspace/src/workspace/glob.rs b/packages/core/workspace/src/workspace/glob.rs index f4a7d503c..94a086f23 100644 --- a/packages/core/workspace/src/workspace/glob.rs +++ b/packages/core/workspace/src/workspace/glob.rs @@ -59,7 +59,7 @@ impl GlobDecision { /// carries only what the pattern text itself got wrong. #[derive(Clone, Debug, Eq, PartialEq)] pub enum GlobParseError { - /// The pattern exceeded [`MAX_PATTERN_BYTES`]. + /// The pattern exceeded `MAX_PATTERN_BYTES`. TooLong { actual: usize, maximum: usize }, /// A `[` was never closed. UnterminatedClass, diff --git a/packages/core/workspace/src/workspace/ignore.rs b/packages/core/workspace/src/workspace/ignore.rs index e465a8130..aa5430532 100644 --- a/packages/core/workspace/src/workspace/ignore.rs +++ b/packages/core/workspace/src/workspace/ignore.rs @@ -304,7 +304,7 @@ impl IgnoreStack { /// Reads the ignore files that `directory` contributes and pushes them. /// /// Returns the stack depth before the push, which the caller restores with - /// [`Self::truncate`] on the way back out. + /// `Self::truncate` on the way back out. /// /// `is_repository_root` makes this directory cut the stack for gitignore /// purposes: a nested checkout is governed by its own files only. That is diff --git a/packages/feature/emacs-lisp/src/obsolete_cl_alias/rule.rs b/packages/feature/emacs-lisp/src/obsolete_cl_alias/rule.rs index 43a98e9ef..28ff05119 100644 --- a/packages/feature/emacs-lisp/src/obsolete_cl_alias/rule.rs +++ b/packages/feature/emacs-lisp/src/obsolete_cl_alias/rule.rs @@ -16,7 +16,7 @@ //! reporting `(dolist (block blocks) …)`, `(let (ll (do t)) …)`, //! `(mapcar (lambda (case) …) …)` and `(defun mail-comma-list-regexp (labels) //! …)` — binding pairs and lambda lists, none of them evaluated as a call. -//! [`could_be_a_call`] asks the two questions that can be answered from the +//! `could_be_a_call` asks the two questions that can be answered from the //! node alone: does the form have an operand *and* a body, and does its first //! argument have the shape the macro's lambda list required. //! diff --git a/packages/feature/generate/src/generate_defsystem/cli/args.rs b/packages/feature/generate/src/generate_defsystem/cli/args.rs index 76f57b99a..54bebbe7e 100644 --- a/packages/feature/generate/src/generate_defsystem/cli/args.rs +++ b/packages/feature/generate/src/generate_defsystem/cli/args.rs @@ -17,11 +17,11 @@ pub struct GenerateDefsystemArgs { /// with underscores turned into hyphens. #[arg(long)] pub name: Option, - /// Write the generated form to /.asd instead of only + /// Write the generated form to `/.asd` instead of only /// printing a plan. #[arg(long)] pub write: bool, - /// With --write, overwrite .asd if it already exists. Without it, + /// With --write, overwrite `.asd` if it already exists. Without it, /// an existing file is left untouched and the command refuses. #[arg(long)] pub force: bool, diff --git a/packages/feature/lint-build-system/src/asdf_system_missing_version/domain.rs b/packages/feature/lint-build-system/src/asdf_system_missing_version/domain.rs index eb33f5e26..03bbbd691 100644 --- a/packages/feature/lint-build-system/src/asdf_system_missing_version/domain.rs +++ b/packages/feature/lint-build-system/src/asdf_system_missing_version/domain.rs @@ -141,7 +141,7 @@ const SUPPORT_SEGMENTS: [&str; 12] = [ /// `cl-prolog2.swi.test`, `cffi-examples`, `named-readtables-test`. ASDF /// calls each of these a *primary* system, so the `/` rule never saw them. /// Recognized by segment instead: the name is split on `-`, `.` and `/`, and -/// any segment in [`SUPPORT_SEGMENTS`] exempts it. +/// any segment in `SUPPORT_SEGMENTS` exempts it. /// /// Matching *any* segment rather than only the last is deliberate — it exempts /// `dref-test-package-inferred` as well as `dref-test` — and so is the diff --git a/packages/feature/lint-build-system/src/defpackage_without_in_package/rule.rs b/packages/feature/lint-build-system/src/defpackage_without_in_package/rule.rs index 5bc794303..1c7043263 100644 --- a/packages/feature/lint-build-system/src/defpackage_without_in_package/rule.rs +++ b/packages/feature/lint-build-system/src/defpackage_without_in_package/rule.rs @@ -23,14 +23,14 @@ //! N−1 of them discarded. //! //! `WholeTree` collapses that to one call per file. It is free rather than -//! merely cheaper, because [`collect_lint_pass`] materializes the root view +//! merely cheaper, because `collect_lint_pass` materializes the root view //! unconditionally — `let root = tree.root_view();`, before the `whole_tree()` //! loop and before the walk — and hands that same view to every `WholeTree` //! rule. So this rule now borrows a view the dispatcher built anyway, where //! under `Heads` it called `root_view()` itself and rebuilt the entire document //! each time. //! -//! [`collect_lint_pass`]: paredit_core_lint_engine::engine::dispatch +//! `collect_lint_pass`: paredit_core_lint_engine::engine::dispatch //! //! Being dispatched on every file rather than only on files with a package //! declaration is what the guard pair in [`examine_file`] pays for, and it is diff --git a/packages/feature/lint-build-system/src/support.rs b/packages/feature/lint-build-system/src/support.rs index fe87aca3f..1c00c15b8 100644 --- a/packages/feature/lint-build-system/src/support.rs +++ b/packages/feature/lint-build-system/src/support.rs @@ -4,7 +4,7 @@ //! //! # Evaluation context //! -//! The quote machinery below ([`QuoteState`], [`for_each_evaluated_subview`], +//! The quote machinery below (`QuoteState`, [`for_each_evaluated_subview`], //! [`is_unevaluated_at`]) is a deliberate copy of //! `paredit-feature-lint-condition-system`'s `support.rs`, not a new design and //! not a cross-package dependency. Two independent counters are required diff --git a/packages/feature/lint-call-shape/src/support.rs b/packages/feature/lint-call-shape/src/support.rs index 519a3d042..a914f07c0 100644 --- a/packages/feature/lint-call-shape/src/support.rs +++ b/packages/feature/lint-call-shape/src/support.rs @@ -4,7 +4,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`], [`for_each_evaluated_subview`], +//! `QuoteState`, [`for_each_evaluated_subview`], //! [`for_each_evaluated_subview_where`] and [`is_unevaluated_at`] are copied //! from `paredit-feature-lint-condition-system`'s `support.rs` — tests included //! — deliberately as a copy rather than as a dependency: a lint feature package diff --git a/packages/feature/lint-carp-idiom/src/support.rs b/packages/feature/lint-carp-idiom/src/support.rs index 9f3f42266..e6c9f9786 100644 --- a/packages/feature/lint-carp-idiom/src/support.rs +++ b/packages/feature/lint-carp-idiom/src/support.rs @@ -3,7 +3,7 @@ //! //! Nothing here runs per visited node. Every helper is called from inside a //! rule that has already matched its head, and the expensive one -//! ([`is_unevaluated_at`]) is called only once a finding is otherwise ready to +//! (`is_unevaluated_at`) is called only once a finding is otherwise ready to //! report — it descends from [`SyntaxTree::root_view`], which materializes the //! whole document, so calling it before the cheap head check costs orders of //! magnitude more per invocation than the check it guards. @@ -40,7 +40,7 @@ //! (`docs/Quasiquotation.md`), neither of which the reader recognizes as a //! prefix; that is a deliberate omission rather than an oversight, since //! recognizing them would make the interior of every `` ` `` template read as -//! code and *add* findings on macro bodies. [`QuoteState::quasi`] therefore +//! code and *add* findings on macro bodies. `QuoteState::quasi` therefore //! never counts back down for Carp, so everything textually inside a `` ` `` //! template reads as data. That suppresses findings rather than inventing //! them, which is the side to be wrong on. diff --git a/packages/feature/lint-clojure-depth/src/support.rs b/packages/feature/lint-clojure-depth/src/support.rs index 0bceeea3b..352716c76 100644 --- a/packages/feature/lint-clojure-depth/src/support.rs +++ b/packages/feature/lint-clojure-depth/src/support.rs @@ -5,7 +5,7 @@ //! # Evaluation context //! //! The quote machinery below (`QuoteState` — private — plus -//! [`for_each_evaluated_subview_where`] and [`is_unevaluated_at`]) is a +//! `for_each_evaluated_subview_where` and [`is_unevaluated_at`]) is a //! deliberate copy of `paredit-feature-lint-clojure-idiom`'s `support.rs`, //! semantics included. It is copied rather than depended on because a feature //! package must not depend on another feature package (§4.2), and it is copied @@ -34,7 +34,7 @@ //! [`is_unevaluated_at`] materializes the enclosing top-level form, so calling //! it on every head match would cost that form's size once per candidate. //! -//! [`root_child_containing`] binary-searches the top level with +//! `root_child_containing` binary-searches the top level with //! [`SyntaxTree::root_child_span`], which is an index into a slice and a field //! read. The obvious spelling — `select_path(&Path::root_child(i))?.span()` — //! heap-allocates a `Vec` *per probe*, so the search alone would diff --git a/packages/feature/lint-clojure-idiom/src/lib.rs b/packages/feature/lint-clojure-idiom/src/lib.rs index cbfc26b91..2c4233fc7 100644 --- a/packages/feature/lint-clojure-idiom/src/lib.rs +++ b/packages/feature/lint-clojure-idiom/src/lib.rs @@ -551,8 +551,16 @@ mod engine_pass_tests { total } - let small = elapsed_nanos(500); - let large = elapsed_nanos(1000); + fn median_elapsed_nanos(forms: usize) -> u128 { + let mut samples = std::array::from_fn::<_, 5, _>(|_| elapsed_nanos(forms)); + samples.sort_unstable(); + samples[samples.len() / 2] + } + + let _ = elapsed_nanos(500); + let _ = elapsed_nanos(1000); + let small = median_elapsed_nanos(500); + let large = median_elapsed_nanos(1000); // 6x rather than 2x: this runs under a loaded shared sandbox alongside // other test binaries, and the point is to catch T×T, which is 4x on a // quiet machine and far more on a busy one. diff --git a/packages/feature/lint-clojure-idiom/src/support.rs b/packages/feature/lint-clojure-idiom/src/support.rs index a78c3d036..4c4272f76 100644 --- a/packages/feature/lint-clojure-idiom/src/support.rs +++ b/packages/feature/lint-clojure-idiom/src/support.rs @@ -31,7 +31,7 @@ //! Two forms make this harder than the reader alone suggests, because they hold //! unevaluated code with **no prefix at all** — `case`'s test constants and //! `(comment …)`'s whole body. Both were found reporting false positives on -//! real code; see [`ChildEvaluation`] and this package's README. +//! real code; see `ChildEvaluation` and this package's README. //! //! # Cost //! @@ -323,7 +323,7 @@ pub fn for_each_evaluated_subview_where( /// visitor and again in its own `(quote …)` test. /// - **The stack is pre-sized**, so a function body does not grow it five times. /// -/// The quote model is the *same* [`QuoteState`], not a second copy of it: that +/// The quote model is the *same* `QuoteState`, not a second copy of it: that /// is the whole point of it living here, and a private re-derivation is the /// mistake this module's header is about. pub fn for_each_evaluated_call( @@ -733,7 +733,7 @@ fn is_realization_barrier(node: &ExpressionView) -> bool { /// Whether `view` reaches one of `names` **without crossing an eager /// realizer**. /// -/// This is [`mentions_any_symbol`] with the barrier described on +/// This is `mentions_any_symbol` with the barrier described on /// [`EAGER_REALIZER_HEADS`]: a resource mentioned only underneath a `doall` is /// already in memory by the time the lazy wrapper is returned, so it does not /// make the wrapper a defect. diff --git a/packages/feature/lint-compile-time/src/eval_when_execute_only/domain.rs b/packages/feature/lint-compile-time/src/eval_when_execute_only/domain.rs index ef00d74ea..3351179c5 100644 --- a/packages/feature/lint-compile-time/src/eval_when_execute_only/domain.rs +++ b/packages/feature/lint-compile-time/src/eval_when_execute_only/domain.rs @@ -49,7 +49,7 @@ //! and common idiom. //! //! What actually matters is whether the body reaches the compiler **at all**, -//! which is [`EvalWhenSituations::reaches_the_compiler`]. +//! which is `EvalWhenSituations::reaches_the_compiler`. //! //! # Deliberate limits //! diff --git a/packages/feature/lint-compile-time/src/support.rs b/packages/feature/lint-compile-time/src/support.rs index 00f741640..a59d92c79 100644 --- a/packages/feature/lint-compile-time/src/support.rs +++ b/packages/feature/lint-compile-time/src/support.rs @@ -17,7 +17,7 @@ //! down. //! //! That distinction is not incidental here, it is the whole of -//! [`crate::macro_helper_not_compile_time`]: a helper called from a macro's +//! `crate::macro_helper_not_compile_time`: a helper called from a macro's //! quasiquote *template* runs at the expansion's run time and needs nothing at //! compile time, while the same call one comma deeper runs at macroexpansion //! time and does. Both were checked against SBCL 2.6.0 and behave exactly that @@ -67,7 +67,7 @@ //! # `scratch_cache` is deliberately not used //! //! `RuleContext::scratch_cache` looks like the right home for -//! [`crate::macro_helper_not_compile_time`]'s per-file set of same-file +//! `crate::macro_helper_not_compile_time`'s per-file set of same-file //! `defun` names. It is not usable: the slot holds **one type per file's //! pass**, `paredit-feature-lint-repl-debug` already stores its evaluated-forms //! walk there (`packages/feature/lint-repl-debug/src/support.rs:612`), and a diff --git a/packages/feature/lint-concurrency/src/support.rs b/packages/feature/lint-concurrency/src/support.rs index 2743271d8..02c3aa6c5 100644 --- a/packages/feature/lint-concurrency/src/support.rs +++ b/packages/feature/lint-concurrency/src/support.rs @@ -268,7 +268,7 @@ pub fn is_unevaluated_at(tree: &SyntaxTree, target: ByteSpan) -> bool { /// /// The chain starts at the top-level form rather than at the virtual document /// root, because materializing the root is what made this whole-file work (see -/// [`root_child_containing`]). Nothing is lost: the root is +/// `root_child_containing`). Nothing is lost: the root is /// [`ExpressionKind::Root`], so `list_head` of it is `None`, and both consumers /// read the chain only through `list_head` — a `with-…`/`unwind-protect` test /// and a `let`/`let*` test, neither of which the root could ever satisfy. A diff --git a/packages/feature/lint-condition-depth/src/support.rs b/packages/feature/lint-condition-depth/src/support.rs index f0bd9feaa..f9fd4b96a 100644 --- a/packages/feature/lint-condition-depth/src/support.rs +++ b/packages/feature/lint-condition-depth/src/support.rs @@ -4,7 +4,7 @@ //! //! # Copied, deliberately //! -//! The [`QuoteState`] quote model and [`is_unevaluated_at`] are copied from +//! The `QuoteState` quote model and [`is_unevaluated_at`] are copied from //! `paredit-feature-lint-condition-system::support`, which is what the other //! lint packages do with it. A consolidation of that helper into //! `packages/core` is in flight; when it lands this module should be deleted @@ -325,7 +325,7 @@ fn mentions_define_condition(source: &str) -> bool { impl ConditionHierarchy { /// Reads every `define-condition` reachable as code in one file, guarded by - /// [`mentions_define_condition`] so a file that defines none pays one byte + /// `mentions_define_condition` so a file that defines none pays one byte /// scan instead of a walk. #[must_use] pub fn collect(tree: &SyntaxTree) -> Self { diff --git a/packages/feature/lint-condition-system/src/restart_case_clause_without_report/domain.rs b/packages/feature/lint-condition-system/src/restart_case_clause_without_report/domain.rs index fe89b93a1..e9584410c 100644 --- a/packages/feature/lint-condition-system/src/restart_case_clause_without_report/domain.rs +++ b/packages/feature/lint-condition-system/src/restart_case_clause_without_report/domain.rs @@ -17,7 +17,7 @@ //! For those, the bare name *is* the interface: a reader of the debugger's //! restart list already knows what `ABORT` does, and a handler invokes it by //! that name rather than by reading its report. Demanding a `:report` there -//! flags idiomatic, correct code, so [`STANDARD_RESTARTS`] clauses are neither +//! flags idiomatic, correct code, so `STANDARD_RESTARTS` clauses are neither //! flagged nor counted — they are not clauses this rule has an opinion about, //! so putting them in the denominator would understate the rate for the clauses //! it does. @@ -169,7 +169,7 @@ pub fn examine_restart_case( /// Collects every `:report`-less restart clause in one file, with the number of /// restart clauses this rule has an opinion about as the denominator beside -/// them — every clause scanned except the [`STANDARD_RESTARTS`] ones. +/// them — every clause scanned except the `STANDARD_RESTARTS` ones. /// /// A dialect this rule does not model is reported as unmodelled rather than as /// clean: an empty finding list means "every restart here explains itself" for diff --git a/packages/feature/lint-condition-system/src/support.rs b/packages/feature/lint-condition-system/src/support.rs index 76f054867..623371b09 100644 --- a/packages/feature/lint-condition-system/src/support.rs +++ b/packages/feature/lint-condition-system/src/support.rs @@ -366,7 +366,7 @@ fn mentions_define_condition(source: &str) -> bool { impl ConditionHierarchy { /// Reads every `define-condition` reachable as code in one file. /// - /// A whole-file walk, guarded by [`mentions_define_condition`] so that a + /// A whole-file walk, guarded by `mentions_define_condition` so that a /// file which defines no condition at all — the common case for the rules /// that consult the hierarchy, since a `(signal 'app-error …)` usually /// names a type defined in some *other* file — pays one byte scan instead. diff --git a/packages/feature/lint-conditional/src/support.rs b/packages/feature/lint-conditional/src/support.rs index 9aa0c16d8..e2bf0ce93 100644 --- a/packages/feature/lint-conditional/src/support.rs +++ b/packages/feature/lint-conditional/src/support.rs @@ -11,7 +11,7 @@ //! steps, not tree-many — and every rule here calls it *only once it already //! has a finding to report*. //! -//! The two counters in [`QuoteState`] are not interchangeable and a single +//! The two counters in `QuoteState` are not interchangeable and a single //! `i32` depth counter is wrong for both: a comma inside `'(…)` is a comma //! character in a literal list, so `hard` never clears, while a comma inside //! `` `(…) `` escapes back to code, so `quasi` counts up and down. A node one diff --git a/packages/feature/lint-contract-annotation/src/clojure_pre_post_vacuous/domain.rs b/packages/feature/lint-contract-annotation/src/clojure_pre_post_vacuous/domain.rs index 4dd30b24b..bc0faee6e 100644 --- a/packages/feature/lint-contract-annotation/src/clojure_pre_post_vacuous/domain.rs +++ b/packages/feature/lint-contract-annotation/src/clojure_pre_post_vacuous/domain.rs @@ -59,7 +59,7 @@ use crate::support::{ /// The one place this rule's dialect is decided. /// -/// Both [`crate::clojure_pre_post_vacuous::rule::Rule::dialect_scope`] and +/// Both `crate::clojure_pre_post_vacuous::rule::Rule::dialect_scope` and /// [`build_clojure_pre_post_vacuous_report`]'s `dialect_modelled` flag read it, /// so the engine's view of which dialects this rule runs for and the standalone /// report's claim about which dialects it measured cannot drift apart. diff --git a/packages/feature/lint-contract-annotation/src/support.rs b/packages/feature/lint-contract-annotation/src/support.rs index 5cc66e71d..c9bb70038 100644 --- a/packages/feature/lint-contract-annotation/src/support.rs +++ b/packages/feature/lint-contract-annotation/src/support.rs @@ -405,7 +405,7 @@ const MAX_LEADING_BODY_FORMS: usize = 16; /// the shape that makes a rule quadratic inside one large function. /// /// Costs no `ExpressionView` except for the `declare` forms themselves, and at -/// most [`MAX_LEADING_BODY_FORMS`] of those. +/// most `MAX_LEADING_BODY_FORMS` of those. pub fn with_leading_declarations( tree: &SyntaxTree, target: ByteSpan, diff --git a/packages/feature/lint-contract-annotation/src/typed_racket_arity_mismatch/domain.rs b/packages/feature/lint-contract-annotation/src/typed_racket_arity_mismatch/domain.rs index 0e06d5770..38fb9881b 100644 --- a/packages/feature/lint-contract-annotation/src/typed_racket_arity_mismatch/domain.rs +++ b/packages/feature/lint-contract-annotation/src/typed_racket_arity_mismatch/domain.rs @@ -91,7 +91,7 @@ use crate::support::{ /// Racket *alone*: `leftover-print-debug` and `self-recursive-tail-call` both /// name `Dialect::Racket`, but each does so inside a broad list of eight or ten /// dialects, and neither encodes anything Racket-specific. Both -/// [`crate::typed_racket_arity_mismatch::rule::Rule::dialect_scope`] and +/// `crate::typed_racket_arity_mismatch::rule::Rule::dialect_scope` and /// [`build_typed_racket_arity_mismatch_report`]'s `dialect_modelled` flag read /// this constant, so the engine's view and the report's claim cannot drift. pub const SCOPE: RuleDialectScope = RuleDialectScope::new(&[Dialect::Racket]); diff --git a/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/args.rs b/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/args.rs index 048f980aa..383e71a6c 100644 --- a/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/args.rs +++ b/packages/feature/lint-control-flow/src/malformed_iteration_spec/cli/args.rs @@ -13,12 +13,7 @@ pub struct MalformedIterationSpecReportArgs { /// Override extension-based dialect detection for every file. #[arg(long)] pub dialect: Option, - // rustdoc reads `[result]` as an intra-doc link and warns that it does not - // resolve. Escaping it would silence the warning and change this line, - // which clap renders verbatim as `--fail-on-violation`'s help text - and - // the CLI surface is pinned by the capabilities golden. The warning is the - // cheaper of the two. - /// Exit with failure when any dolist/dotimes spec is not (var form [result]). + /// Exit with failure when any dolist/dotimes spec is not (var form optional-result). #[arg(long)] pub fail_on_violation: bool, /// Output format for agent consumption. diff --git a/packages/feature/lint-control-flow/src/support.rs b/packages/feature/lint-control-flow/src/support.rs index 891b4ec80..22cf1209f 100644 --- a/packages/feature/lint-control-flow/src/support.rs +++ b/packages/feature/lint-control-flow/src/support.rs @@ -27,7 +27,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`] and [`for_each_evaluated_subview`] are copied from +//! `QuoteState` and [`for_each_evaluated_subview`] are copied from //! `paredit-feature-lint-condition-system`'s `support.rs` (and its copy in //! `paredit-feature-lint-testing`), tests included, deliberately as a copy //! rather than as a dependency: a lint feature package depending on another diff --git a/packages/feature/lint-custom/src/pattern.rs b/packages/feature/lint-custom/src/pattern.rs index e089d78cf..96eb9a053 100644 --- a/packages/feature/lint-custom/src/pattern.rs +++ b/packages/feature/lint-custom/src/pattern.rs @@ -10,7 +10,7 @@ //! `Pattern`/[`Template`] using the selector's own [`classify_atom`] //! tokenizer for every spelling but two, and every match, rewrite, and //! rewrite-hazard check downstream ([`super::pass`]) is the selector's own -//! [`match_all`], [`plan_rewrite`], and [`Template::render`] — unchanged, +//! `match_all`, `plan_rewrite`, and [`Template::render`] — unchanged, //! unduplicated. //! //! ## The two spellings kept at their old meaning @@ -223,7 +223,7 @@ fn push(before: &mut Vec, after: &mut Vec, rest: &Option /// [`paredit inspect check --paredit-config`]'s migration signal. /// /// Detected on the already-converted [`Pattern`] rather than re-walking the -/// source view: [`convert`]'s literal-atom fallback for this exact case is +/// source view: `convert`'s literal-atom fallback for this exact case is /// the only way a bare, unprefixed `Pattern::Atom` with the text `...` can /// appear in a pattern this module produced, so finding one *is* finding a /// rule still written in the old style. diff --git a/packages/feature/lint-data-structure/src/support.rs b/packages/feature/lint-data-structure/src/support.rs index cd377a49b..06fe56273 100644 --- a/packages/feature/lint-data-structure/src/support.rs +++ b/packages/feature/lint-data-structure/src/support.rs @@ -31,7 +31,7 @@ //! files with zero findings, which is exactly that cost. //! //! [`locate`]'s top-level step uses [`SyntaxTree::root_child_span`] rather than -//! `select_path(&Path::root_child(i))`: [`Path`] owns a `Vec`, so the obvious +//! `select_path(&Path::root_child(i))`: `Path` owns a `Vec`, so the obvious //! spelling heap-allocates once per sibling scanned. use paredit_core_syntax::sexpr::{ diff --git a/packages/feature/lint-destructive-sequence/src/discarded_destructive_sequence_result.rs b/packages/feature/lint-destructive-sequence/src/discarded_destructive_sequence_result.rs index 07524b8ed..e62c6add4 100644 --- a/packages/feature/lint-destructive-sequence/src/discarded_destructive_sequence_result.rs +++ b/packages/feature/lint-destructive-sequence/src/discarded_destructive_sequence_result.rs @@ -262,7 +262,7 @@ fn destroyed_variable(view: &ExpressionView) -> Option<&str> { atom_text(argument) } -/// [`destroyed_variable`], for the corpus audit's funnel. +/// `destroyed_variable`, for the corpus audit's funnel. /// /// The audit needs to count condition 1's survivors independently of the rule's /// dispatch, so that a zero-finding sweep can say *which* condition did the diff --git a/packages/feature/lint-destructive-sequence/src/support.rs b/packages/feature/lint-destructive-sequence/src/support.rs index a322e0c6f..6de2b8ef6 100644 --- a/packages/feature/lint-destructive-sequence/src/support.rs +++ b/packages/feature/lint-destructive-sequence/src/support.rs @@ -18,7 +18,7 @@ //! //! # The quote model is two counters, not a depth //! -//! [`QuoteState`] is copied from `paredit-feature-lint-condition-system::support`, +//! `QuoteState` is copied from `paredit-feature-lint-condition-system::support`, //! as the other lint packages do with it; a consolidation into `packages/core` //! is in flight, and when it lands this module should be deleted. //! diff --git a/packages/feature/lint-documentation/src/support.rs b/packages/feature/lint-documentation/src/support.rs index a918cb002..27bd77e66 100644 --- a/packages/feature/lint-documentation/src/support.rs +++ b/packages/feature/lint-documentation/src/support.rs @@ -7,7 +7,7 @@ //! subject by different routes: //! //! - A **docstring is a node** — a string literal sitting in a definition's -//! body or in a fixed slot. [`docstring_of`] reads it from the +//! body or in a fixed slot. `docstring_of` reads it from the //! [`ExpressionView`] the dispatcher already handed the rule, so those rules //! are `HeadFilter::Heads` and never look at the file as a whole. //! - A **comment is not a node.** The parser keeps comments in a list beside @@ -18,7 +18,7 @@ //! //! # Evaluation context //! -//! The quote machinery below ([`QuoteState`], [`is_unevaluated_at`]) is a +//! The quote machinery below (`QuoteState`, [`is_unevaluated_at`]) is a //! deliberate copy of `paredit-feature-lint-build-system`'s `support.rs`, not a //! new design and not a cross-package dependency. Two independent counters are //! required because `'` and `` ` `` are not the same thing: @@ -275,7 +275,7 @@ pub fn string_literal_text(view: &ExpressionView) -> Option { /// two whose docstring is a plain string literal a width or an example can be /// read out of; a `(:documentation "…")` option is read by /// [`documentation_option`] instead, and `defstruct`'s slot-or-docstring -/// position is deliberately not read at all (see [`docstring_of`]). +/// position is deliberately not read at all (see `docstring_of`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DocstringPlace { /// At the head of the body, after the lambda list: `defun`, `defmacro`, diff --git a/packages/feature/lint-documentation/src/todo_fixme_no_attribution/domain.rs b/packages/feature/lint-documentation/src/todo_fixme_no_attribution/domain.rs index 59ab29898..54fb44194 100644 --- a/packages/feature/lint-documentation/src/todo_fixme_no_attribution/domain.rs +++ b/packages/feature/lint-documentation/src/todo_fixme_no_attribution/domain.rs @@ -50,7 +50,7 @@ use crate::support::comment_prose; const MARKERS: [&str; 5] = ["FIXME", "XXX", "BUG", "HACK", "TODO"]; /// The attribution shapes this rule accepts, as documentation. The predicate -/// is [`has_attribution`]; this list is what it is asserted against. +/// is `has_attribution`; this list is what it is asserted against. /// /// | Shape | Example | /// | --- | --- | diff --git a/packages/feature/lint-elisp-depth/src/repeating_timer_handle_discarded/rule.rs b/packages/feature/lint-elisp-depth/src/repeating_timer_handle_discarded/rule.rs index 36b4f273a..a6fa4ae37 100644 --- a/packages/feature/lint-elisp-depth/src/repeating_timer_handle_discarded/rule.rs +++ b/packages/feature/lint-elisp-depth/src/repeating_timer_handle_discarded/rule.rs @@ -43,7 +43,7 @@ //! positive-literal REPEAT buys, and it is linear precisely because //! `root_view()` is linear in the file. //! -//! [`repeats`] is therefore load-bearing for cost as well as for correctness: +//! `repeats` is therefore load-bearing for cost as well as for correctness: //! it is the last check that can reject without reaching the root. Across GNU //! Emacs's `lisp/` tree plus 2585 third-party files there are 500 timer call //! sites and only **33** carry a positive literal REPEAT, so the expensive diff --git a/packages/feature/lint-fennel-janet-depth/src/fennel_bad_unpack/domain.rs b/packages/feature/lint-fennel-janet-depth/src/fennel_bad_unpack/domain.rs index 6d930d4e2..90e063607 100644 --- a/packages/feature/lint-fennel-janet-depth/src/fennel_bad_unpack/domain.rs +++ b/packages/feature/lint-fennel-janet-depth/src/fennel_bad_unpack/domain.rs @@ -54,7 +54,7 @@ //! and confirmed by running it: `(select "#" (.. (table.unpack ["a" "b" "c"])))` //! is `3`, so nothing was dropped. `fennel-ls`'s own documentation example for //! this lint — ``(.. (unpack ["a" "b" "c"])) ; Only concatenates "a"`` — is -//! therefore incorrect as written for Fennel 1.6.1. [`PASSTHROUGH_UNARY`] is +//! therefore incorrect as written for Fennel 1.6.1. `PASSTHROUGH_UNARY` is //! that measured exception list. //! //! Every other operator does truncate even at one argument, because it diff --git a/packages/feature/lint-form-shape/src/defpackage_quoted/domain.rs b/packages/feature/lint-form-shape/src/defpackage_quoted/domain.rs index 4e3db1714..fb6d5d4ee 100644 --- a/packages/feature/lint-form-shape/src/defpackage_quoted/domain.rs +++ b/packages/feature/lint-form-shape/src/defpackage_quoted/domain.rs @@ -49,7 +49,7 @@ pub struct DefpackageQuotedItem { pub span: ByteSpan, /// The clause keyword, lowercased (`:export`, ...). /// - /// One of [`DESIGNATOR_CLAUSES`], so it is `&'static str` rather than the + /// One of `DESIGNATOR_CLAUSES`, so it is `&'static str` rather than the /// spelling read from the source: the set is closed and the report leads /// each row with it. pub clause: &'static str, diff --git a/packages/feature/lint-form-shape/src/redundant_quote/domain.rs b/packages/feature/lint-form-shape/src/redundant_quote/domain.rs index 7b13b1c90..795276519 100644 --- a/packages/feature/lint-form-shape/src/redundant_quote/domain.rs +++ b/packages/feature/lint-form-shape/src/redundant_quote/domain.rs @@ -116,7 +116,7 @@ pub struct RedundantQuoteItem { pub span: ByteSpan, pub literal: String, /// Which self-evaluating category the literal falls in, from - /// [`LiteralKind::describe`]'s closed set. + /// `LiteralKind::describe`'s closed set. pub kind: &'static str, } diff --git a/packages/feature/lint-generic-dispatch/src/initialization_primary_without_call_next_method/domain.rs b/packages/feature/lint-generic-dispatch/src/initialization_primary_without_call_next_method/domain.rs index e9e7fcc35..a832a75af 100644 --- a/packages/feature/lint-generic-dispatch/src/initialization_primary_without_call_next_method/domain.rs +++ b/packages/feature/lint-generic-dispatch/src/initialization_primary_without_call_next_method/domain.rs @@ -57,7 +57,7 @@ //! (CLHS 7.1.7). It reaches the protocol without the indirection. //! - **`shared-initialize`**, `update-instance-for-different-class` and //! `update-instance-for-redefined-class` are no longer modelled at all. See -//! [`INITIALIZATION_GENERICS`]. +//! `INITIALIZATION_GENERICS`. //! //! With both, the rule reports nothing anywhere in that corpus. //! diff --git a/packages/feature/lint-hy-depth/src/support.rs b/packages/feature/lint-hy-depth/src/support.rs index 6fbb9eb5e..4e912ceb6 100644 --- a/packages/feature/lint-hy-depth/src/support.rs +++ b/packages/feature/lint-hy-depth/src/support.rs @@ -26,7 +26,7 @@ //! //! # Why the quote model cannot count down for Hy //! -//! [`QuoteState`] is the two-counter model from +//! `QuoteState` is the two-counter model from //! `packages/feature/lint-condition-system/src/support.rs` — `hard: bool` plus //! `quasi: u32`. A single `i32` depth counter is wrong and has shipped in this //! workspace as a false-positive source twice. A consolidation of the several diff --git a/packages/feature/lint-hy-depth/tests/corpus.rs b/packages/feature/lint-hy-depth/tests/corpus.rs index 6b1f04fd1..d0bf8f5d0 100644 --- a/packages/feature/lint-hy-depth/tests/corpus.rs +++ b/packages/feature/lint-hy-depth/tests/corpus.rs @@ -56,6 +56,23 @@ fn multi_clause_try_count(source: &str) -> usize { count } +fn except_binding(clause: &str) -> &str { + let mut depth = 0; + for (index, character) in clause.char_indices() { + match character { + '[' => depth += 1, + ']' => { + depth -= 1; + if depth == 0 { + return clause[..=index].trim(); + } + } + _ => {} + } + } + clause.lines().next().unwrap_or("").trim() +} + #[test] fn the_clean_fixture_parses_and_offers_real_candidates() { // Without this the next test is a false clean: a fixture the reader @@ -104,8 +121,7 @@ fn each_dangerous_shape_is_reported_at_its_own_clause() { let (finding, _) = outcome.into_parts(); let start = finding.span.start().get(); let end = finding.span.end().get().min(DANGEROUS.len()); - // The first line of the reported clause identifies it. - DANGEROUS[start..end].lines().next().unwrap_or("").trim() + except_binding(&DANGEROUS[start..end]) }) .collect(); reported.sort_unstable(); diff --git a/packages/feature/lint-hy-depth/tests/fixtures/clean.hy b/packages/feature/lint-hy-depth/tests/fixtures/clean.hy index e02cc3dec..ffbc35191 100644 --- a/packages/feature/lint-hy-depth/tests/fixtures/clean.hy +++ b/packages/feature/lint-hy-depth/tests/fixtures/clean.hy @@ -5,106 +5,77 @@ ;; The point of this file is the *denominator*: the corpus test asserts that it ;; contains handler chains for the rule to judge. A clean sweep over a file ;; with no multi-clause `try` would prove nothing at all. - (import os json sys) + (import pathlib [Path]) ;; Narrow to broad: the ordinary correct shape. -(defn load-config [path] - (try - (json.loads (.read-text (Path path))) - (except [e FileNotFoundError] - (print "no config at" path) - {}) - (except [e json.JSONDecodeError] - (print "bad json" e) - {}) - (except [e OSError] - (print "io error" e) - {}))) +(defn load-config + [path] + (try (json.loads (.read-text (Path path))) + (except [e FileNotFoundError] (print "no config at" path) {}) + (except [e json.JSONDecodeError] (print "bad json" e) {}) + (except [e OSError] (print "io error" e) {}))) ;; A tuple of types, then a broader clause. Neither type is covered above. -(defn fetch [key store] - (try - (get store key) - (except [e [KeyError IndexError]] - None) - (except [e Exception] - (print "unexpected" e) - None))) +(defn fetch + [key store] + (try (get store key) + (except [e [KeyError IndexError]] None) + (except [e Exception] (print "unexpected" e) None))) ;; Sibling types under one parent: neither covers the other. -(defn convert [text] - (try - (int text) - (except [e ValueError] - 0) - (except [e TypeError] - 0))) +(defn convert + [text] + (try (int text) (except [e ValueError] 0) (except [e TypeError] 0))) ;; A project exception class beside a builtin. This layer cannot see what ;; `ConfigError` inherits from, so it must not guess in either direction. (defclass ConfigError [Exception]) -(defn strict-load [path] - (try - (load-config path) - (except [e ConfigError] - (sys.exit 2)) - (except [e OSError] - (sys.exit 1)))) +(defn strict-load + [path] + (try (load-config path) + (except [e ConfigError] (sys.exit 2)) + (except [e OSError] (sys.exit 1)))) ;; `Exception` before a project class is deliberately NOT reported: the class ;; may derive from `BaseException` directly, in which case this clause is live. -(defn tolerant [path] - (try - (load-config path) - (except [e Exception] - (print "generic")) - (except [e ConfigError] - (print "specific")))) +(defn tolerant + [path] + (try (load-config path) + (except [e Exception] (print "generic")) + (except [e ConfigError] (print "specific")))) ;; A single-clause `try` can never earn a finding, and `else`/`finally` are not ;; except clauses. -(defn read-once [path] - (try - (.read-text (Path path)) - (except [e OSError] - "") - (else - (print "ok")) - (finally - (print "done")))) +(defn read-once + [path] + (try (.read-text (Path path)) + (except [e OSError] "") + (else (print "ok")) + (finally (print "done")))) ;; A bare `except` that is last shadows nothing. Reporting its breadth is the ;; sibling package's `hy-bare-except`, not this rule's business. -(defn best-effort [thunk] - (try - (thunk) - (except [e ValueError] - None) - (except [] - None))) +(defn best-effort + [thunk] + (try (thunk) (except [e ValueError] None) (except [] None))) ;; A macro template. Nothing inside a Hy quasiquote is code as far as this ;; package is concerned, so even a genuinely shadowed chain here is not ;; reported. (defmacro with-logging [#* body] - `(try - ~@body - (except [e Exception] - (print "failed")) - (except [e ValueError] - (print "value")))) + `(try ~@body + (except [e Exception] (print "failed")) + (except [e ValueError] (print "value")))) ;; `#(...)` is a tuple, a self-evaluating constant rather than a call. (setv shapes #(1 2 3)) ;; A dotted exception type this layer cannot resolve. -(defn socket-read [sock] - (try - (.recv sock 1024) - (except [e socket.timeout] - b"") - (except [e OSError] - b""))) +(defn socket-read + [sock] + (try (.recv sock 1024) + (except [e socket.timeout] b"") + (except [e OSError] b""))) diff --git a/packages/feature/lint-hy-depth/tests/fixtures/dangerous.hy b/packages/feature/lint-hy-depth/tests/fixtures/dangerous.hy index a33e10bb9..0434f3471 100644 --- a/packages/feature/lint-hy-depth/tests/fixtures/dangerous.hy +++ b/packages/feature/lint-hy-depth/tests/fixtures/dangerous.hy @@ -5,84 +5,60 @@ ;; ;; The audit's single real-world finding was this file's `import-order` shape, ;; found in `atisharma/hyjinx`: `ImportError` before `ModuleNotFoundError`. - (import os json sys) ;; A supertype first. `ValueError` never runs. -(defn broad-first [text] - (try - (int text) - (except [e Exception] - (print "generic")) - (except [e ValueError] - (print "never runs")))) +(defn broad-first + [text] + (try (int text) + (except [e Exception] (print "generic")) + (except [e ValueError] (print "never runs")))) ;; The shape found in real third-party code: `ModuleNotFoundError` is a ;; subclass of `ImportError`, so the second clause is dead. -(defn import-order [name] - (try - (__import__ name) - (except [e ImportError] - None) - (except [e ModuleNotFoundError] - None))) +(defn import-order + [name] + (try (__import__ name) + (except [e ImportError] None) + (except [e ModuleNotFoundError] None))) ;; The same type twice. -(defn duplicated [store key] - (try - (get store key) - (except [e KeyError] - 1) - (except [e KeyError] - 2))) +(defn duplicated + [store key] + (try (get store key) (except [e KeyError] 1) (except [e KeyError] 2))) ;; A bare clause first kills both clauses after it. -(defn bare-first [thunk] - (try - (thunk) - (except [] - None) - (except [e ValueError] - None) - (except [e OSError] - None))) +(defn bare-first + [thunk] + (try (thunk) + (except [] None) + (except [e ValueError] None) + (except [e OSError] None))) ;; `BaseException` covers even a class this layer has never heard of. (defclass AppError [Exception]) -(defn base-first [thunk] - (try - (thunk) - (except [e BaseException] - None) - (except [e AppError] - None))) +(defn base-first + [thunk] + (try (thunk) (except [e BaseException] None) (except [e AppError] None))) ;; Every type of a tuple already covered: `KeyError` and `IndexError` are both ;; `LookupError`s. -(defn tuple-covered [store key] - (try - (get store key) - (except [e LookupError] - 1) - (except [e [KeyError IndexError]] - 2))) +(defn tuple-covered + [store key] + (try (get store key) + (except [e LookupError] 1) + (except [e [KeyError IndexError]] 2))) ;; `IOError` is not a subclass of `OSError`, it *is* `OSError`, so this is a ;; duplicate rather than a narrowing. -(defn alias-duplicate [path] - (try - (open path) - (except [e OSError] - None) - (except [e IOError] - None))) +(defn alias-duplicate + [path] + (try (open path) (except [e OSError] None) (except [e IOError] None))) ;; Transitivity: `UnicodeDecodeError` -> `UnicodeError` -> `ValueError`. -(defn transitive [raw] - (try - (.decode raw "utf-8") - (except [e ValueError] - "") - (except [e UnicodeDecodeError] - ""))) +(defn transitive + [raw] + (try (.decode raw "utf-8") + (except [e ValueError] "") + (except [e UnicodeDecodeError] ""))) diff --git a/packages/feature/lint-introspection/src/support.rs b/packages/feature/lint-introspection/src/support.rs index 4796ae730..670449ac1 100644 --- a/packages/feature/lint-introspection/src/support.rs +++ b/packages/feature/lint-introspection/src/support.rs @@ -12,7 +12,7 @@ //! cannot tell on its own whether it is code. Without [`is_unevaluated_at`], //! every rule in this package would fire on template text. //! -//! [`QuoteState`] and [`for_each_evaluated_subview`] are copied from +//! `QuoteState` and [`for_each_evaluated_subview`] are copied from //! `paredit-feature-lint-testing`'s `support.rs` (itself a copy of //! `paredit-feature-lint-condition-system`'s), tests included, deliberately as a //! copy rather than as a dependency: a lint feature package depending on another diff --git a/packages/feature/lint-iteration-flow/src/loop_syntax.rs b/packages/feature/lint-iteration-flow/src/loop_syntax.rs index 1cc04aabe..888585e64 100644 --- a/packages/feature/lint-iteration-flow/src/loop_syntax.rs +++ b/packages/feature/lint-iteration-flow/src/loop_syntax.rs @@ -28,13 +28,13 @@ //! entirely and the first pass never sees it. `(loop for i from 1 to count //! collect i)` is the everyday shape that needs this: `count` there is a //! parameter, not an accumulation clause. So the token following any of -//! [`OPERAND_INTRODUCERS`] is forced to [`TokenRole::Operand`] regardless of +//! `OPERAND_INTRODUCERS` is forced to [`TokenRole::Operand`] regardless of //! its spelling. Like the first pass this over-collects, and like the first //! pass over-collecting can only lose findings. //! - **An unmodelled sub-grammar aborts the whole form.** See below. //! //! A reader prefix on a token has the same effect: `'collect` is quoted data -//! and never the `collect` clause, so [`symbol_word`] refuses any prefixed +//! and never the `collect` clause, so `symbol_word` refuses any prefixed //! atom. //! //! # What this reader does not attempt @@ -226,7 +226,7 @@ pub fn is_subclause_keyword(word: &str) -> bool { } /// Whether `word` opens body code, and so may appear only after every variable -/// clause. See [`BODY_CLAUSE_KEYWORDS`] for why this is narrower than the +/// clause. See `BODY_CLAUSE_KEYWORDS` for why this is narrower than the /// CLHS `main-clause` production. #[must_use] pub fn is_body_clause_keyword(word: &str) -> bool { diff --git a/packages/feature/lint-lfe-carp-depth/src/illegal_guard_call/domain.rs b/packages/feature/lint-lfe-carp-depth/src/illegal_guard_call/domain.rs index 644c1c293..9a07bee7a 100644 --- a/packages/feature/lint-lfe-carp-depth/src/illegal_guard_call/domain.rs +++ b/packages/feature/lint-lfe-carp-depth/src/illegal_guard_call/domain.rs @@ -109,7 +109,7 @@ pub const DIALECTS: [Dialect; 1] = [Dialect::Lfe]; /// so this table was produced by *running* that predicate over /// `erlang:module_info(exports)` plus every operator spelling, under the same /// OTP the probes used. It reported `GUARD_SET_COUNT 67`, and -/// [`tests::the_guard_table_matches_the_enumerated_size`] pins that count so a +/// `tests::the_guard_table_matches_the_enumerated_size` pins that count so a /// hand edit cannot silently drop an entry. /// /// Sorted by name then arity, which [`is_guard_bif`] relies on. diff --git a/packages/feature/lint-macro-authoring/src/support.rs b/packages/feature/lint-macro-authoring/src/support.rs index a33bdbd67..e2e584faa 100644 --- a/packages/feature/lint-macro-authoring/src/support.rs +++ b/packages/feature/lint-macro-authoring/src/support.rs @@ -1,7 +1,7 @@ //! What the macro-authoring rules share: whether a matched form is *code*, and //! how to read a macro lambda list. //! -//! Every rule here declares [`HeadFilter::Heads`], so the engine hands it one +//! Every rule here declares `HeadFilter::Heads`, so the engine hands it one //! matched form and no context whatsoever. Two things follow, and this module //! is both: //! @@ -704,7 +704,7 @@ impl MacroLambdaList { /// because it is bound to an environment object rather than to a form. /// /// Nested destructuring names are not collected: only the first element of a -/// sublist is, matching [`lambda_list_names`], which under-reads rather than +/// sublist is, matching `lambda_list_names`, which under-reads rather than /// inventing names. #[must_use] pub fn caller_supplied_parameters(list: &ExpressionView) -> Vec { diff --git a/packages/feature/lint-numeric/src/support.rs b/packages/feature/lint-numeric/src/support.rs index f5ca732b8..ed0d832f7 100644 --- a/packages/feature/lint-numeric/src/support.rs +++ b/packages/feature/lint-numeric/src/support.rs @@ -224,7 +224,7 @@ pub fn is_unevaluated_at(tree: &SyntaxTree, target: ByteSpan) -> bool { /// `(eq x "s")` has the bug the rule is named for, and the expansion is where it /// will bite. /// -/// Hence `hard` alone rather than [`QuoteState::is_data`]. The two-counter state +/// Hence `hard` alone rather than `QuoteState::is_data`. The two-counter state /// is what makes the distinction expressible at all: a single depth counter /// cannot tell `'(a ,(eq x "s"))` — still data, the comma is a literal comma — /// from `` `(a ,(eq x "s")) ``, which is code. @@ -407,7 +407,7 @@ fn is_type_specifier_position( /// one-argument call to `eql` and never was. /// /// The verdict needs the candidate's *ancestors*, which no head-matched node -/// carries, so this descends from the root exactly as [`quote_state_at`] does. +/// carries, so this descends from the root exactly as `quote_state_at` does. /// The two questions are independent and both are asked only once a finding /// already exists, so ordinary code never reaches [`SyntaxTree::root_view`]. /// @@ -648,7 +648,7 @@ fn is_binding_position( /// reports as a four-argument `equal` call. /// /// The verdict needs the candidate's *ancestors*, which no head-matched node -/// carries, so this descends from the root exactly as [`quote_state_at`] does, +/// carries, so this descends from the root exactly as `quote_state_at` does, /// and — like every other guard here — is asked only once a finding already /// exists, so ordinary code never reaches [`SyntaxTree::root_view`]. /// diff --git a/packages/feature/lint-numeric/src/t_comparison/domain.rs b/packages/feature/lint-numeric/src/t_comparison/domain.rs index 57cdd7874..690a34dde 100644 --- a/packages/feature/lint-numeric/src/t_comparison/domain.rs +++ b/packages/feature/lint-numeric/src/t_comparison/domain.rs @@ -74,7 +74,7 @@ impl Finding for TComparisonItem { /// parsing JSON. /// /// A closed set of four, already normalized to lowercase `&'static str` by - /// [`equality_operator`] — the source casing is not retained, so this is + /// `equality_operator` — the source casing is not retained, so this is /// the canonical name rather than whatever the file spelled. fn kind(&self) -> &'static str { self.operator diff --git a/packages/feature/lint-object-system/src/method_qualifier_typo/domain.rs b/packages/feature/lint-object-system/src/method_qualifier_typo/domain.rs index 5e2bc8ac1..79626bb36 100644 --- a/packages/feature/lint-object-system/src/method_qualifier_typo/domain.rs +++ b/packages/feature/lint-object-system/src/method_qualifier_typo/domain.rs @@ -20,7 +20,7 @@ //! //! Either counts wherever the file compiler would process it as a top-level //! form, which includes inside `eval-when`, `progn`, `locally`, `macrolet` and -//! `symbol-macrolet` — see [`TOP_LEVEL_WRAPPERS`]. Wrapping a +//! `symbol-macrolet` — see `TOP_LEVEL_WRAPPERS`. Wrapping a //! `define-method-combination` in `(eval-when (:compile-toplevel …) …)` so //! later forms in the file can use it is ordinary, not exotic. //! diff --git a/packages/feature/lint-object-system/src/support.rs b/packages/feature/lint-object-system/src/support.rs index c33f0d564..c628b327c 100644 --- a/packages/feature/lint-object-system/src/support.rs +++ b/packages/feature/lint-object-system/src/support.rs @@ -45,7 +45,7 @@ pub struct FormSite { /// True inside a `` ` ``/`(quasiquote …)` region that no `,`/`,@` escapes, /// and true unconditionally inside a `'`/`(quote …)` region — a comma there /// escapes nothing, because there is no backquote for it to escape. See - /// [`QuoteState`]. A `(defmethod …)` inside quoted data defines no method, + /// `QuoteState`. A `(defmethod …)` inside quoted data defines no method, /// and a rule that flags one is reporting on a list literal. pub quoted: bool, /// Whether the match *is* one of the file's top-level forms. diff --git a/packages/feature/lint-package-hygiene/src/support.rs b/packages/feature/lint-package-hygiene/src/support.rs index a6e78a434..6fae1f757 100644 --- a/packages/feature/lint-package-hygiene/src/support.rs +++ b/packages/feature/lint-package-hygiene/src/support.rs @@ -3,7 +3,7 @@ //! //! # Evaluation context //! -//! The quote machinery below ([`QuoteState`], [`for_each_evaluated_subview`], +//! The quote machinery below (`QuoteState`, [`for_each_evaluated_subview`], //! [`is_unevaluated_at`]) is a deliberate copy of //! `paredit-feature-lint-condition-system`'s `support.rs` — by way of //! `paredit-feature-lint-build-system`'s span-local refinement of it — and not diff --git a/packages/feature/lint-performance/src/linear_search_in_loop.rs b/packages/feature/lint-performance/src/linear_search_in_loop.rs index 056d568cd..446d67fa1 100644 --- a/packages/feature/lint-performance/src/linear_search_in_loop.rs +++ b/packages/feature/lint-performance/src/linear_search_in_loop.rs @@ -7,7 +7,7 @@ //! What makes the finding worth making is the word *same*: the collection must //! not depend on the loop. `(dolist (x xs) (member y x))` searches something //! different each round and cannot be hoisted, so it is not reported. That -//! check — [`crate::shared::mentions_any`] against the loop's own variables — +//! check — `crate::shared::mentions_any` against the loop's own variables — //! is the rule, and everything else is bookkeeping. //! //! Report-only: the rewrite introduces a new binding before the loop and diff --git a/packages/feature/lint-performance/src/repeated_hash_table_lookup_same_key.rs b/packages/feature/lint-performance/src/repeated_hash_table_lookup_same_key.rs index 45b10510a..f49a18710 100644 --- a/packages/feature/lint-performance/src/repeated_hash_table_lookup_same_key.rs +++ b/packages/feature/lint-performance/src/repeated_hash_table_lookup_same_key.rs @@ -21,7 +21,7 @@ //! //! - **Only one of them may run.** `(if p (gethash :a h) (gethash :a h))` is not //! a repeat: exactly one arm executes. Every reported pair is checked with -//! [`branches_are_exclusive`], which reads the conditional arms each lookup +//! `branches_are_exclusive`, which reads the conditional arms each lookup //! sits under. A lookup in an `if`'s *test* and one in its `then` arm are //! still a pair, because whenever the arm runs the test ran. //! diff --git a/packages/feature/lint-portability/src/char_code_limit_loop.rs b/packages/feature/lint-portability/src/char_code_limit_loop.rs index 6243c3ec7..a91724f48 100644 --- a/packages/feature/lint-portability/src/char_code_limit_loop.rs +++ b/packages/feature/lint-portability/src/char_code_limit_loop.rs @@ -57,8 +57,8 @@ //! variable walks its own subtree. The `clean/forms/*` benchmarks lint files //! with zero findings, so that first compare is all this rule costs there. //! -//! [`mentions_a_byte_wide_bound`] is a *performance* device and not a -//! correctness guard: [`read_loop`] independently rejects every form it +//! `mentions_a_byte_wide_bound` is a *performance* device and not a +//! correctness guard: `read_loop` independently rejects every form it //! rejects, so deleting the call site changes no finding — which a mutation run //! confirmed. It is pinned by a direct assertion on the predicate rather than //! through the rule's output, because there is no output to observe. diff --git a/packages/feature/lint-portability/src/support.rs b/packages/feature/lint-portability/src/support.rs index bb4b6c9f6..34517a7f4 100644 --- a/packages/feature/lint-portability/src/support.rs +++ b/packages/feature/lint-portability/src/support.rs @@ -8,7 +8,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`] is copied from `paredit-feature-lint-condition-system`'s +//! `QuoteState` is copied from `paredit-feature-lint-condition-system`'s //! `support.rs` (and its sibling copy in `paredit-feature-lint-testing`), //! tests included, deliberately as a copy rather than as a dependency: a lint //! feature package depending on another lint feature package would be a new diff --git a/packages/feature/lint-racket-depth/src/support.rs b/packages/feature/lint-racket-depth/src/support.rs index 3a1fc3204..b404d9ce0 100644 --- a/packages/feature/lint-racket-depth/src/support.rs +++ b/packages/feature/lint-racket-depth/src/support.rs @@ -170,7 +170,7 @@ pub struct NodeContext { /// when the node is top level or its parent has no symbol head. pub parent_head: Option, /// Some ancestor of the node is a macro-defining form, so the node is part - /// of a template rather than of code. See [`MACRO_DEFINITION_HEADS`]. + /// of a template rather than of code. See `MACRO_DEFINITION_HEADS`. pub in_macro_template: bool, } diff --git a/packages/feature/lint-racket-depth/tests/fixtures/clean.rkt b/packages/feature/lint-racket-depth/tests/fixtures/clean.rkt index 6c16f712f..9ccecbd7d 100644 --- a/packages/feature/lint-racket-depth/tests/fixtures/clean.rkt +++ b/packages/feature/lint-racket-depth/tests/fixtures/clean.rkt @@ -5,56 +5,49 @@ ;; ;; This file is checked by `racket` itself in the report accompanying the ;; package, not only by the linter. -(require racket/match racket/list - racket/contract) +(require racket/match racket/list racket/contract) -(provide (contract-out - [classify (-> any/c symbol?)] - [tally (-> (listof exact-integer?) exact-integer?)]) render-all) +(provide + (contract-out [classify (-> any/c symbol?)] + [tally (-> (listof exact-integer?) exact-integer?)]) + render-all) ;; A `match` whose catch-all is last, which is the overwhelmingly common and ;; entirely correct shape. -(define - (classify value) - (match - value - [(? number?) 'number] - [(? string?) 'string] - [(list _ ...) 'list] - [_ 'other])) +(define (classify value) + (match value + [(? number?) 'number] + [(? string?) 'string] + [(list _ ...) 'list] + [_ 'other])) ;; A guarded clause is not a catch-all: the guard can fail, so the clause ;; below it is live. -(define - (bucket n) - (match - n - [x #:when (< x 0) 'negative] - [x #:when (zero? x) 'zero] - [0 'unreachable-but-not-by-catch-all] - [_ 'positive])) +(define (bucket n) + (match n + [x #:when (< x 0) 'negative] + [x #:when (zero? x) 'zero] + [0 'unreachable-but-not-by-catch-all] + [_ 'positive])) ;; Quoted symbols are literals, not bindings. (define (direction->delta d) (match d ['north -1] ['south 1] [_ 0])) ;; `match-lambda` with the catch-all last. -(define - describe - (match-lambda - [(list 'ok value) value] - [(list 'error message) message] - [_ "unknown"])) +(define describe + (match-lambda [(list 'ok value) value] + [(list 'error message) message] + [_ "unknown"])) ;; A `begin0` that genuinely sequences: it returns the first form's value and ;; still runs the cleanup. (define (pop! box-cell) (begin0 (unbox box-cell) (set-box! box-cell '()))) ;; A `case-lambda` that genuinely dispatches on arity. -(define - tally - (case-lambda - [(xs) (tally xs 0)] - [(xs start) (for/fold ([total start]) ([x (in-list xs)]) (+ total x))])) +(define tally + (case-lambda [(xs) (tally xs 0)] + [(xs start) + (for/fold ([total start]) ([x (in-list xs)]) (+ total x))])) ;; A `parameterize` that genuinely rebinds. (define (render-all items) @@ -69,35 +62,34 @@ (classify item)))) ;; A comprehension bound to a name has its value read. -(define - (summarise items) - (let ([labels (for/list - ([item (in-list items)]) - (classify item))] - [count (length items)]) - (when (positive? count) - (displayln count)) - labels)) +(define (summarise items) + (let ([labels (for/list + ([item (in-list items)]) + (classify item))] + [count (length items)]) + (when (positive? count) + (displayln count)) + labels)) ;; A named `let`, whose body starts one position later than an ordinary one. -(define - (drain queue) - (let loop - ([remaining queue] [seen '()]) - (unless (null? remaining) - (displayln (car remaining))) - (if (null? remaining) (reverse seen) - (loop (cdr remaining) (cons (car remaining) seen))))) +(define (drain queue) + (let loop + ([remaining queue] [seen '()]) + (unless (null? remaining) + (displayln (car remaining))) + (if (null? remaining) + (reverse seen) + (loop (cdr remaining) (cons (car remaining) seen))))) ;; `let*`, `letrec` and a plain `lambda`, all with their comprehension last. -(define - transform - (lambda (items) - (let* ([n (length items)] - [scaled (for/list ([i (in-range n)]) (* i 2))]) - (letrec - ([go - (lambda (xs) - (if (null? xs) '() - (cons (car xs) (go (cdr xs)))))]) - (go scaled))))) +(define transform + (lambda (items) + (let* ([n (length items)] + [scaled (for/list ([i (in-range n)]) (* i 2))]) + (letrec + ([go + (lambda (xs) + (if (null? xs) + '() + (cons (car xs) (go (cdr xs)))))]) + (go scaled))))) diff --git a/packages/feature/lint-racket-depth/tests/fixtures/dangerous.rkt b/packages/feature/lint-racket-depth/tests/fixtures/dangerous.rkt index 0c96a64a6..a5a6e39c5 100644 --- a/packages/feature/lint-racket-depth/tests/fixtures/dangerous.rkt +++ b/packages/feature/lint-racket-depth/tests/fixtures/dangerous.rkt @@ -9,9 +9,8 @@ ;; racket-match-unreachable-clause: the `[_ 'other]` clause matches every ;; value, so `[(? string?) 'str]` below it can never run. `raco make` compiles ;; this without a word and `(classify "hi")` returns 'other. -(define - (classify value) - (match value [(? number?) 'number] [_ 'other] [(? string?) 'string])) +(define (classify value) + (match value [(? number?) 'number] [_ 'other] [(? string?) 'string])) ;; racket-begin0-single-form: with one form there is no sequence, so this is ;; exactly `(compute-total)`. @@ -28,9 +27,8 @@ ;; racket-for-comprehension-value-discarded: the list is built, filled and ;; dropped, because it is not the last form of the body. `for` does the same ;; iteration without allocating it. -(define - (report items) - (for/list ([item (in-list items)]) (displayln item)) - 'done) +(define (report items) + (for/list ([item (in-list items)]) (displayln item)) + 'done) (define (compute-total) 42) diff --git a/packages/feature/lint-repl-debug/src/commented_repl_transcript/domain.rs b/packages/feature/lint-repl-debug/src/commented_repl_transcript/domain.rs index 579917614..f700feee7 100644 --- a/packages/feature/lint-repl-debug/src/commented_repl_transcript/domain.rs +++ b/packages/feature/lint-repl-debug/src/commented_repl_transcript/domain.rs @@ -18,7 +18,7 @@ //! # The heuristic, and why it stays conservative //! //! A block is a run of comment lines with nothing but a newline between them -//! (no blank line, no code) — see [`comment_blocks`]. Within a block, a line +//! (no blank line, no code) — see `comment_blocks`. Within a block, a line //! is prompt-shaped when its text (marker and leading space stripped) matches //! `[\w.*+-]+>\s...` (a package/prompt name, `>`, then the typed form) and //! result-shaped when it starts with `=>`. A block is flagged only when it diff --git a/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/rule.rs b/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/rule.rs index f70672db7..47a4cde79 100644 --- a/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/rule.rs +++ b/packages/feature/lint-repl-debug/src/leftover_format_debug_marker/rule.rs @@ -16,7 +16,7 @@ use paredit_core_syntax::sexpr::ExpressionView; /// Report-only, deliberately, and for a reason distinct from its siblings: this /// rule's marker test is wrong, not just its safety argument. /// -/// [`super::domain::contains_debug_marker`] requires a word boundary *before* +/// `super::domain::contains_debug_marker` requires a word boundary *before* /// the marker and none after it. Its own doc gives `"UNDEBUGGABLE"` as the /// non-match, which holds only because the `U` precedes `DEBUG`. Nothing stops /// `DEBUG` from matching when it is the *start* of an ordinary word, so diff --git a/packages/feature/lint-repl-debug/src/leftover_inspect_call/rule.rs b/packages/feature/lint-repl-debug/src/leftover_inspect_call/rule.rs index 7d516a717..37ac8db1e 100644 --- a/packages/feature/lint-repl-debug/src/leftover_inspect_call/rule.rs +++ b/packages/feature/lint-repl-debug/src/leftover_inspect_call/rule.rs @@ -50,7 +50,7 @@ use paredit_core_syntax::sexpr::ExpressionView; /// /// Three narrower remedies were measured and rejected: /// -/// - **Narrowing [`crate::leftover_inspect_call::domain::HEADS`] to `inspect` +/// - **Narrowing `crate::leftover_inspect_call::domain::HEADS` to `inspect` /// alone.** That drops 2,382 of 2,388 findings and leaves 6 — all of which /// are `cl-cc:inspect`/`cl-cc/debug:inspect`, a *user's own* debug library, /// flagged inside that library's own test file. Narrowing leaves a rule with diff --git a/packages/feature/lint-repl-debug/src/leftover_print_debug/domain.rs b/packages/feature/lint-repl-debug/src/leftover_print_debug/domain.rs index 859e2fca0..7f95ff6b8 100644 --- a/packages/feature/lint-repl-debug/src/leftover_print_debug/domain.rs +++ b/packages/feature/lint-repl-debug/src/leftover_print_debug/domain.rs @@ -9,7 +9,7 @@ //! history warns about). //! //! Removal safety (whether a fix is offered at all) is -//! [`paredit_feature_lint_repl_debug::support`]'s job: a flagged call is only +//! `paredit_feature_lint_repl_debug::support`'s job: a flagged call is only //! auto-removed when it is a bare top-level form or a non-last form of its //! enclosing implicit-progn/`cond`-clause body. diff --git a/packages/feature/lint-repl-debug/src/leftover_print_debug/rule.rs b/packages/feature/lint-repl-debug/src/leftover_print_debug/rule.rs index cbd65bf7a..e6922b9ca 100644 --- a/packages/feature/lint-repl-debug/src/leftover_print_debug/rule.rs +++ b/packages/feature/lint-repl-debug/src/leftover_print_debug/rule.rs @@ -24,7 +24,7 @@ use paredit_core_syntax::sexpr::ExpressionView; /// The removal-safety analysis in [`crate::support`] establishes that deleting /// the call cannot change the *value* of its enclosing body. It cannot /// establish that the call was a debug leftover rather than the program's -/// output, and in every dialect in [`DIALECTS`] the heads it matches are that +/// output, and in every dialect in `DIALECTS` the heads it matches are that /// dialect's ordinary way to write to a stream: Scheme's `display`, Racket's /// `displayln`, Emacs Lisp's `message`, Clojure's `println`, Janet's, Fennel's /// and Hy's `print`, and — the case that looks most like a genuine debug diff --git a/packages/feature/lint-repl-debug/src/leftover_trace_call/rule.rs b/packages/feature/lint-repl-debug/src/leftover_trace_call/rule.rs index 749903426..d0f563c5e 100644 --- a/packages/feature/lint-repl-debug/src/leftover_trace_call/rule.rs +++ b/packages/feature/lint-repl-debug/src/leftover_trace_call/rule.rs @@ -50,7 +50,7 @@ use paredit_core_syntax::sexpr::ExpressionView; /// document the *following* form. /// /// Narrowing was measured and rejected. Dropping `untrace` from -/// [`crate::leftover_trace_call::domain::HEADS`] leaves 13 fixable findings, all +/// `crate::leftover_trace_call::domain::HEADS` leaves 13 fixable findings, all /// still false positives, so it removes no defect. Gating to one dialect is /// unavailable: every one of the 19 is Common Lisp, the stratum a narrowing /// would have to keep. diff --git a/packages/feature/lint-repl-debug/src/support.rs b/packages/feature/lint-repl-debug/src/support.rs index 10dfbf883..cd0ff0e6f 100644 --- a/packages/feature/lint-repl-debug/src/support.rs +++ b/packages/feature/lint-repl-debug/src/support.rs @@ -40,15 +40,15 @@ //! binding of `step` to `x`. Naively visiting every list's children //! generically would report `(defun process (step x) ...)`'s lambda list as //! a leftover `step` call — `step` is a common loop-variable name, so this is -//! not a hypothetical. [`binding_position`] names, for `defun`/`defmacro`/ +//! not a hypothetical. `binding_position` names, for `defun`/`defmacro`/ //! `lambda`/`let`/`let*`/`flet`/`labels`/`macrolet`, exactly which child is a -//! lambda-list or bindings-list, and [`visit_bindings`] walks it with rules +//! lambda-list or bindings-list, and `visit_bindings` walks it with rules //! that never treat a name or parameter position as a candidate — only a //! `let`/`let*` binding's own init form, which is genuinely evaluated code. //! //! # A second trap: the matched head may not be the operator it names //! -//! [`binding_position`] keeps a *binding-list* position from being misread as +//! `binding_position` keeps a *binding-list* position from being misread as //! a call, but says nothing about the *body* of the same form. Under //! `(flet ((time (thunk) …)) (time fn))` the inner `(time fn)` is a call to //! the file's own local function, not to `cl:time` — and unwrapping it to @@ -73,9 +73,9 @@ //! by a local-function binder is not detected. //! - **`do`/`do*`/`prog`/`prog*`/`multiple-value-bind`/`destructuring-bind`.** //! These have the same call-shaped-binding ambiguity as the forms above but -//! are not in [`binding_position`]'s table, so a variable there named after +//! are not in `binding_position`'s table, so a variable there named after //! a target debug head can still produce a false-positive *report*. Never a -//! false-positive *fix*: none of these heads is in [`body_start`], so +//! false-positive *fix*: none of these heads is in `body_start`, so //! nothing inside one is ever [`RemovalSafety::Safe`]. //! - **`flet`/`labels`/`macrolet` local function bodies.** Each binding //! `(name lambda-list body...)` has its own implicit-progn body, but this @@ -87,7 +87,7 @@ //! conservative under-approximation, never an unsafe removal. //! - **`&optional`/`&key` lambda-list default-value forms**, e.g. the `(foo)` //! in `(x (foo))` within `(defun f (&optional (x (foo))) ...)`. A lambda -//! list is not descended into at all (see [`BindingShape::LambdaList`]), so +//! list is not descended into at all (see `BindingShape::LambdaList`), so //! a leftover debug call there is silently missed — a false negative, not a //! false positive. //! - **Vector/set reader literals** (`#(...)`, `#{...}`). Whether their @@ -360,7 +360,7 @@ pub fn walk_evaluated_forms<'a>( /// seven rules ever reads past a candidate's immediate children (confirmed /// by grep across every `leftover_*::domain` module: the deepest access is /// `view.children.get(1)` / `.get(2)` read as atoms, never -/// `.children[1].children`), so [`shallow_clone`] copies exactly one level — +/// `.children[1].children`), so `shallow_clone` copies exactly one level — /// the matched node's own fields plus its immediate children's own fields — /// and replaces every grandchild with an empty `children` vec. A first /// attempt at this cache used a plain recursive `.clone()` here and @@ -507,7 +507,7 @@ fn is_candidate_head(head: &str) -> bool { /// scanned-form denominator the standalone `inspect ` commands report. /// /// The two are deliberately separate. `candidates` is filtered down to heads -/// that could match ([`CANDIDATE_HEADS`]), but `scanned_form_count` counts +/// that could match (`CANDIDATE_HEADS`), but `scanned_form_count` counts /// *every* node the walk visits, atoms included — which is what each rule's /// `collect_*` reported before the walk was shared, and what its /// `scanned_form_count` JSON/text field has always meant. Deriving the @@ -592,11 +592,11 @@ pub fn compute_evaluated_forms(root: &ExpressionView) -> EvaluatedForms { /// /// 1. A first version stored each candidate with a plain `.clone()`, which /// for an [`ExpressionView`] is a *whole-subtree* deep copy. See -/// [`EvaluatedCandidate`]'s doc and [`shallow_clone`]. +/// [`EvaluatedCandidate`]'s doc and `shallow_clone`. /// 2. Even shallow, cloning at *every* call site still allocated far more /// than the seven allocation-free walks it replaced — CI measured /// +17.3%/+17.2%, worse than before the unification. See -/// [`CANDIDATE_HEADS`], the head-union filter that fixed it. +/// `CANDIDATE_HEADS`, the head-union filter that fixed it. /// /// With both corrections the clean path allocates nothing: no candidate is /// constructed unless its head could match a rule, so a file with nothing to diff --git a/packages/feature/lint-safety/src/declarative_style_score.rs b/packages/feature/lint-safety/src/declarative_style_score.rs index 8e9f0c603..4ebf6636c 100644 --- a/packages/feature/lint-safety/src/declarative_style_score.rs +++ b/packages/feature/lint-safety/src/declarative_style_score.rs @@ -96,7 +96,7 @@ pub const META: RuleMeta = RuleMeta::new( /// The percentage (0-100) of `root`'s top-level forms that are purely /// declarative, and how many forms that count was taken over. `None` when the -/// file has fewer than [`MIN_JUDGED_FORMS`] top-level forms — too few for a +/// file has fewer than `MIN_JUDGED_FORMS` top-level forms — too few for a /// percentage to mean anything. #[must_use] pub fn declarative_score(root: &ExpressionView) -> Option<(u32, usize)> { diff --git a/packages/feature/lint-safety/src/support.rs b/packages/feature/lint-safety/src/support.rs index 4d55a7f8a..4261af841 100644 --- a/packages/feature/lint-safety/src/support.rs +++ b/packages/feature/lint-safety/src/support.rs @@ -28,7 +28,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`] and the descent in [`context_at`] are copied from +//! `QuoteState` and the descent in [`context_at`] are copied from //! `paredit-feature-lint-testing`'s `support.rs`, which copied them from //! `paredit-feature-lint-condition-system`'s, deliberately as a copy rather //! than as a dependency: a lint feature package depending on another lint diff --git a/packages/feature/lint-scheme-idiom/src/support.rs b/packages/feature/lint-scheme-idiom/src/support.rs index 94486a8ea..5ad9a5804 100644 --- a/packages/feature/lint-scheme-idiom/src/support.rs +++ b/packages/feature/lint-scheme-idiom/src/support.rs @@ -181,7 +181,7 @@ pub struct NodeContext { /// when the node is top level or its parent has no symbol head. pub parent_head: Option, /// Some ancestor of the node is a macro-defining form, so the node is part - /// of a template rather than of code. See [`MACRO_DEFINITION_HEADS`]. + /// of a template rather than of code. See `MACRO_DEFINITION_HEADS`. pub in_macro_template: bool, } diff --git a/packages/feature/lint-scheme-idiom/tests/fixtures/clean.rkt b/packages/feature/lint-scheme-idiom/tests/fixtures/clean.rkt index f34c3fd14..856ee9c6a 100644 --- a/packages/feature/lint-scheme-idiom/tests/fixtures/clean.rkt +++ b/packages/feature/lint-scheme-idiom/tests/fixtures/clean.rkt @@ -6,32 +6,29 @@ (provide tokenize summarize) ;; `let*` that uses its sequential scope, written with brackets. -(define - (tokenize text) - (let* ([trimmed (string-trim text)] - [parts (string-split trimmed)] - [kept (filter non-empty-string? parts)]) - kept)) +(define (tokenize text) + (let* ([trimmed (string-trim text)] + [parts (string-split trimmed)] + [kept (filter non-empty-string? parts)]) + kept)) ;; A named let that recurs, bracketed bindings. -(define - (summarize items) - (let loop - ([rest items] [total 0]) - (cond - [(null? rest) total] - [else - (loop (cdr rest) (+ total (string-length (car rest))))]))) +(define (summarize items) + (let loop + ([rest items] [total 0]) + (cond + [(null? rest) total] + [else + (loop (cdr rest) (+ total (string-length (car rest))))]))) ;; Non-tail named-let recursion: correct, and never to be reported. -(define - (interleave xs sep) - (let join - ([rest xs]) - (cond - [(null? rest) '()] - [(null? (cdr rest)) (list (car rest))] - [else (cons (car rest) (cons sep (join (cdr rest))))]))) +(define (interleave xs sep) + (let join + ([rest xs]) + (cond + [(null? rest) '()] + [(null? (cdr rest)) (list (car rest))] + [else (cons (car rest) (cons sep (join (cdr rest))))]))) ;; `begin` sequencing two effects. (define (log-and-return value) (begin (displayln value) value)) @@ -53,23 +50,21 @@ ;; `let*` with independent literal bindings would be reported -- so this one is ;; deliberately written as the `let` it should be. -(define - (defaults) - (let ([width 80] - [height 24]) - (cons width height))) +(define (defaults) + (let ([width 80] + [height 24]) + (cons width height))) ;; Quoted data mentioning every anchored head. -(define - samples - '((begin x) - (let* ([a 1] - [b 2]) - b) - (let loop - () - (void)) - (memq 5 x))) +(define samples + '((begin x) + (let* ([a 1] + [b 2]) + b) + (let loop + () + (void)) + (memq 5 x))) ;; A vector constant that looks like a call. (define heads #(begin let let* memq assq)) diff --git a/packages/feature/lint-scheme-idiom/tests/fixtures/clean.scm b/packages/feature/lint-scheme-idiom/tests/fixtures/clean.scm index 69637bfe9..e3a035ce6 100644 --- a/packages/feature/lint-scheme-idiom/tests/fixtures/clean.scm +++ b/packages/feature/lint-scheme-idiom/tests/fixtures/clean.scm @@ -20,47 +20,46 @@ (define (queue-empty? q) (and (null? (queue-front q)) (null? (queue-back q)))) ;; `begin` sequencing two effects: doing its job. -(define - (queue-push! q value) - (begin (set-queue-back! q (cons value (queue-back q))) q)) +(define (queue-push! q value) + (begin (set-queue-back! q (cons value (queue-back q))) q)) ;; A named `let` that actually recurs, in tail position. -(define - (queue-length q) - (let loop - ((items (queue-front q)) (total 0)) - (if (null? items) total - (loop (cdr items) (+ total 1))))) +(define (queue-length q) + (let loop + ((items (queue-front q)) (total 0)) + (if (null? items) + total + (loop (cdr items) (+ total 1))))) ;; A named `let` that recurs in NON-tail position. Correct, idiomatic Scheme: ;; R7RS 3.5 guarantees tail calls, it does not require them. -(define - (queue->list q) - (let build - ((items (queue-back q))) - (if (null? items) '() - (cons (car items) (build (cdr items)))))) +(define (queue->list q) + (let build + ((items (queue-back q))) + (if (null? items) + '() + (cons (car items) (build (cdr items)))))) ;; `let*` that genuinely uses its sequential scope. -(define - (queue-pop! q) - (let* ((front (queue-front q)) - (head - (if (pair? front) (car front) - #f)) - (rest - (if (pair? front) (cdr front) - '()))) - (set-queue-front! q rest) - head)) +(define (queue-pop! q) + (let* ((front (queue-front q)) + (head + (if (pair? front) + (car front) + #f)) + (rest + (if (pair? front) + (cdr front) + '()))) + (set-queue-front! q rest) + head)) ;; `let*` whose initializers are calls: independent by name, but ordered by ;; effect, so converting to `let` would be wrong. -(define - (read-pair) - (let* ((first (read)) - (second (read))) - (cons first second))) +(define (read-pair) + (let* ((first (read)) + (second (read))) + (cons first second))) ;; `eq?` on the types R7RS 6.1 guarantees it for. (define (symbolic? value) (or (eq? value 'none) (eq? value '()) (eq? value #f))) @@ -78,38 +77,34 @@ ;; `eqv?` where the operand is a number or a character, which is what this ;; package asks for. -(define - (digit-value c) - (cond - ((eqv? c #\0) 0) - ((eqv? c #\1) 1) - (else #f))) +(define (digit-value c) + (cond + ((eqv? c #\0) 0) + ((eqv? c #\1) 1) + (else #f))) ;; Quoted data that mentions every head, and must be invisible to all of them. -(define - syntax-samples - '((begin x) - (let* ((a 1) - (b 2)) - b) - (let loop - ((i 0)) - i) - (memq 5 x))) +(define syntax-samples + '((begin x) + (let* ((a 1) + (b 2)) + b) + (let loop + ((i 0)) + i) + (memq 5 x))) ;; A vector constant whose first element is spelled like an operator. The ;; reader makes this a self-evaluating vector (R7RS 4.1.2), not a call. (define operator-names #(begin let let* memq assq)) ;; A macro template whose named let recurs. -(define-syntax - while - (syntax-rules - () - ((_ test body ...) - (let loop - () - (when test - body - ... - (loop)))))) +(define-syntax while + (syntax-rules () + ((_ test body ...) + (let loop + () + (when test + body + ... + (loop)))))) diff --git a/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.rkt b/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.rkt index 0aafcce75..39992a436 100644 --- a/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.rkt +++ b/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.rkt @@ -7,15 +7,13 @@ (define (start!) (begin (open-connection))) ;; scheme-let-star-independent-bindings, bracketed -(define - (window-size) - (let* ([width 80] - [height 24]) - (cons width height))) +(define (window-size) + (let* ([width 80] + [height 24]) + (cons width height))) ;; scheme-named-let-never-recurs, bracketed binding list -(define - (first-item items) - (let scan - ([rest items]) - (car rest))) +(define (first-item items) + (let scan + ([rest items]) + (car rest))) diff --git a/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.scm b/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.scm index c968c9c83..23f7b0941 100644 --- a/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.scm +++ b/packages/feature/lint-scheme-idiom/tests/fixtures/dangerous.scm @@ -6,19 +6,17 @@ ;; scheme-let-star-independent-bindings: two literal initializers, neither of ;; which can see the other. -(define - (window-size) - (let* ((width 80) - (height 24)) - (cons width height))) +(define (window-size) + (let* ((width 80) + (height 24)) + (cons width height))) ;; scheme-memq-assq-literal-key: R7RS 6.4 spells this exact search out as ;; unspecified, and gives `memv` as the one that is not. (define (known-code? codes) (memq 101 codes)) ;; scheme-named-let-never-recurs: `scan` is bound and never called. -(define - (first-line port) - (let scan - ((line (read-line port))) - line)) +(define (first-line port) + (let scan + ((line (read-line port))) + line)) diff --git a/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/domain.rs b/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/domain.rs index dcb46a637..c7043823c 100644 --- a/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/domain.rs +++ b/packages/feature/lint-sequence/src/hash_table_iteration_order_assumed/domain.rs @@ -233,7 +233,7 @@ fn is_unordered_producer(view: &ExpressionView) -> bool { /// # Cost /// /// `car`, `first` and `nth` are dense in ordinary code, so the predicates are -/// ordered cheapest-first: [`accessor_of`] (one byte switch and one string +/// ordered cheapest-first: `accessor_of` (one byte switch and one string /// comparison), then the arity, then `is_paren_list` on the sequence operand — /// which rejects `(car xs)`, `(first row)` and `(nth i items)`, the shapes that /// actually occur, before anything reads a clause or compares a producer name. diff --git a/packages/feature/lint-sequence/src/redundant_into_empty_collection/domain.rs b/packages/feature/lint-sequence/src/redundant_into_empty_collection/domain.rs index edfaad8ab..376e1a4e1 100644 --- a/packages/feature/lint-sequence/src/redundant_into_empty_collection/domain.rs +++ b/packages/feature/lint-sequence/src/redundant_into_empty_collection/domain.rs @@ -166,7 +166,7 @@ fn conversion_for(target: &ExpressionView) -> Option { /// # Cost /// /// One `children.len()` rejects every transducer-arity call, and the -/// `children.is_empty()` inside [`conversion_for`] rejects every call whose +/// `children.is_empty()` inside `conversion_for` rejects every call whose /// target is anything but an empty literal — before any delimiter or prefix is /// read. `into` is not a dense head to begin with. pub fn examine( diff --git a/packages/feature/lint-sequence/src/support.rs b/packages/feature/lint-sequence/src/support.rs index 2fef7056e..b659177db 100644 --- a/packages/feature/lint-sequence/src/support.rs +++ b/packages/feature/lint-sequence/src/support.rs @@ -4,7 +4,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`], [`is_quote_form`] and [`for_each_evaluated_subview`] are +//! `QuoteState`, `is_quote_form` and [`for_each_evaluated_subview`] are //! copied from `paredit-feature-lint-condition-system`'s `support.rs`, tests //! included, and [`is_unevaluated_at`] is copied from //! `paredit-feature-lint-testing`'s — deliberately as a copy rather than as a @@ -206,7 +206,7 @@ pub fn is_unevaluated_at(tree: &SyntaxTree, target: ByteSpan) -> bool { /// exactly the macro bodies it exists to read. `'(nthcdr 0 x)` is a /// three-element list of symbols, and rewriting it to `'x` edits a user's *data /// literal* — which is why the verdict is read on the `hard` counter alone, and -/// never on [`QuoteState::is_data`]. +/// never on `QuoteState::is_data`. /// /// The target's *own* reader prefixes count, and every rule guarded by this /// passes the span of the form it matched. That is deliberate: whether such a diff --git a/packages/feature/lint-string-char/src/support.rs b/packages/feature/lint-string-char/src/support.rs index b4b464229..7fbc1c3b9 100644 --- a/packages/feature/lint-string-char/src/support.rs +++ b/packages/feature/lint-string-char/src/support.rs @@ -216,7 +216,7 @@ pub fn control_string_index(head: &str) -> Option { /// `None` — meaning "there is nothing here this package can analyze" — for /// every one of: /// -/// - a head that is not in [`FORMAT_HEADS`]; +/// - a head that is not in `FORMAT_HEADS`; /// - a call too short to have a control-string slot at all; /// - a *computed* control string (`(format t (banner) x)`), because a control /// string that does not exist in the source cannot be read; diff --git a/packages/feature/lint-testing/src/support.rs b/packages/feature/lint-testing/src/support.rs index 39df3604a..223c54cb7 100644 --- a/packages/feature/lint-testing/src/support.rs +++ b/packages/feature/lint-testing/src/support.rs @@ -26,7 +26,7 @@ //! //! # Quote semantics //! -//! [`QuoteState`] and [`for_each_evaluated_subview`] are copied from +//! `QuoteState` and [`for_each_evaluated_subview`] are copied from //! `paredit-feature-lint-condition-system`'s `support.rs`, tests included, //! deliberately as a copy rather than as a dependency: a lint feature package //! depending on another lint feature package would be a new feature→feature diff --git a/packages/feature/lint-type-declaration/src/support.rs b/packages/feature/lint-type-declaration/src/support.rs index e84b19bb4..38b18d006 100644 --- a/packages/feature/lint-type-declaration/src/support.rs +++ b/packages/feature/lint-type-declaration/src/support.rs @@ -16,7 +16,7 @@ //! body)` put their body at different indices, and CLHS 3.4.11 lets the //! declaration section interleave declarations with one documentation string. //! [`body_start`] and [`declaration_section_end`] are that geometry. -//! - **A type lattice small enough to be right.** [`TypeExcludes`] answers only +//! - **A type lattice small enough to be right.** `TypeExcludes` answers only //! "can this type specifier definitely *not* contain this literal", and only //! for atomic specifiers whose relationship to the modelled literals is //! enumerable. Every compound specifier — `(or null string)` above all — is @@ -590,7 +590,7 @@ impl<'a> TypeDeclaration<'a> { /// /// Both spellings: the long `(type fixnum x y)` and the abbreviated `(fixnum x /// y)`. An abbreviated specifier whose identifier is one of -/// [`NON_TYPE_DECLARATION_IDENTIFIERS`] is not a type declaration, and neither +/// `NON_TYPE_DECLARATION_IDENTIFIERS` is not a type declaration, and neither /// is one whose identifier is a `(…)` list — `((integer 0 10) x)` is not legal /// abbreviated syntax, only `(type (integer 0 10) x)` is. #[must_use] diff --git a/packages/feature/lisp-analysis/src/duplicate_method_report/domain.rs b/packages/feature/lisp-analysis/src/duplicate_method_report/domain.rs index f7eaa480d..b8705c59d 100644 --- a/packages/feature/lisp-analysis/src/duplicate_method_report/domain.rs +++ b/packages/feature/lisp-analysis/src/duplicate_method_report/domain.rs @@ -5,7 +5,7 @@ //! overloading (which requires a *different* specializer list to select //! between methods at dispatch time). //! -//! [`paredit_feature_project_analysis::redefinition_report::domain`] deliberately excludes +//! `paredit_feature_project_analysis::redefinition_report::domain` deliberately excludes //! `Method`-category definitions entirely, since two methods sharing a //! name with different specializers is completely normal CLOS dispatch; //! this report narrows back in on the one shape that IS a bug — the same diff --git a/packages/feature/lisp-analysis/src/macro_hygiene_report/rule/mod.rs b/packages/feature/lisp-analysis/src/macro_hygiene_report/rule/mod.rs index 433fad882..f2e7fed10 100644 --- a/packages/feature/lisp-analysis/src/macro_hygiene_report/rule/mod.rs +++ b/packages/feature/lisp-analysis/src/macro_hygiene_report/rule/mod.rs @@ -36,7 +36,7 @@ //! - Sweeping macro density 0/2/5/10/100% gives ≈0/2/5/10/77% overhead — a //! clean dose-response, with the crossover into measurable cost at about //! **5% macro density**. Real Lisp sits an order of magnitude below that. -//! - [`HEADS`] is what contains it: at 0% macro density the delta is −2.6% +//! - `HEADS` is what contains it: at 0% macro density the delta is −2.6% //! (noise), so widening the head list and adding four registry entries costs //! nothing on the non-macro forms that are almost all of any file. //! diff --git a/packages/feature/schema-check/src/dsl.rs b/packages/feature/schema-check/src/dsl.rs index ba073f113..912c2ae34 100644 --- a/packages/feature/schema-check/src/dsl.rs +++ b/packages/feature/schema-check/src/dsl.rs @@ -200,7 +200,7 @@ pub struct SchemaDef { /// Reads every `(defschema ...)` in one file's text. /// /// `path` names the file only for the diagnostics; nothing is read from disk -/// here, matching [`paredit_feature_migrate::recipe::parse_recipes`]'s own +/// here, matching `paredit_feature_migrate::recipe::parse_recipes`'s own /// contract, so a built-in schema and a user's file would go through one code /// path and fail the same way. pub fn parse_schemas(text: &str, path: &str) -> Result, DslError> { diff --git a/packages/feature/semantic-report/src/effect_report/domain/mod.rs b/packages/feature/semantic-report/src/effect_report/domain/mod.rs index 33ae453ef..5c564671b 100644 --- a/packages/feature/semantic-report/src/effect_report/domain/mod.rs +++ b/packages/feature/semantic-report/src/effect_report/domain/mod.rs @@ -22,13 +22,13 @@ //! //! One case gets help from the value layer: a Common Lisp `if` whose test is //! a `let`/`let*`-bound or `defconstant`-named constant the value layer has -//! already proven. `if` itself is not in [`policy`]'s tables — nothing +//! already proven. `if` itself is not in `policy`'s tables — nothing //! is — so ordinarily its every use defaults the verdict to `Unknown`, same as //! any other unrecognized head, and both branches are walked. When the test's //! value is provably known, the dead branch can never run, so it is skipped //! rather than charged against the definition's purity, and `if` no longer //! counts as an unresolved head. This is deliberately narrow: only two -//! sources are trusted (see [`resolve_constant`]), and a test that is not one +//! sources are trusted (see `resolve_constant`), and a test that is not one //! of them falls straight back to today's behavior, unchanged. mod policy; diff --git a/src/lint/mod.rs b/src/lint/mod.rs index 367229bf6..6fa83b824 100644 --- a/src/lint/mod.rs +++ b/src/lint/mod.rs @@ -10,7 +10,7 @@ //! //! Layout follows the usual split — [`model`] for the vocabulary, [`policy`] //! for decisions that need no tree, [`engine`] for the pass, [`registry`] for -//! the catalogue, and [`rules`] for the rules themselves. +//! the catalogue, and `rules` for the rules themselves. // Phase 2 facade (section 4.1). engine/model/policy/rule now live in // `paredit-core-lint-engine`; `registry` and `rules` stay here, because a diff --git a/tests/cli/analysis_report.rs b/tests/cli/analysis_report.rs index 69ee330bf..ef00e0ef0 100644 --- a/tests/cli/analysis_report.rs +++ b/tests/cli/analysis_report.rs @@ -57,7 +57,7 @@ fn cli_prints_definition_outline() { cmd.args(["inspect", "outline", "--file", "tests/fixtures/sample.el"]) .assert() .success() - .stdout(predicate::str::contains("0\t0..37\tdefun\ttrue")); + .stdout(predicate::str::contains("0\t0..39\tdefun\ttrue")); } #[test] diff --git a/tests/fixtures/corpus/carp.carp b/tests/fixtures/corpus/carp.carp index 2fdff88d4..b869513d5 100644 --- a/tests/fixtures/corpus/carp.carp +++ b/tests/fixtures/corpus/carp.carp @@ -1,50 +1,61 @@ ;; Carp: a statically typed Lisp. Type signatures beside definitions, modules ;; that own their type's functions, borrowed references with `&`, copies with ;; `@`, and flat-pair `cond` ending in a default expression. - (load "Test.carp") -(deftype Account [id String, balance Int]) +(deftype Account [id String balance Int]) (defmodule Account - (doc rich? "Whether the account holds more than the given amount.") - (sig rich? (Fn [&Account Int] Bool)) - (defn rich? [account amount] - (> @(balance account) amount)) - - (sig label (Fn [&Account] String)) - (defn label [account] - (fmt "%s:%d" (id account) @(balance account))) - - (sig withdraw (Fn [Account Int] Account)) - (defn withdraw [account amount] - (let [current @(balance &account)] - (set-balance account (- current amount))))) + (doc rich? "Whether the account holds more than the given amount.") + (sig rich? (Fn [&Account Int] Bool)) + (defn rich? [account amount] (> @(balance account) amount)) + (sig label (Fn [&Account] String)) + (defn label [account] (fmt "%s:%d" (id account) @(balance account))) + (sig withdraw (Fn [Account Int] Account)) + (defn withdraw + [account amount] + (let [current @(balance &account)] + (set-balance account (- current amount))))) (sig classify (Fn [Int] String)) -(defn classify [n] - (cond - (< n 0) @"negative" - (= n 0) @"zero" - (> n 100) @"large" - @"positive")) + +(defn classify + [n] + (cond + (< + n + 0) + @"negative" + (= + n + 0) + @"zero" + (> + n + 100) + @"large" + @"positive")) (sig total (Fn [&(Array Account)] Int)) -(defn total [accounts] - (let-do [running 0] - (foreach [account accounts] - (set! running (+ running @(Account.balance account)))) - running)) - -(defndynamic repeat-form [n form] - (if (= n 0) - '() - (cons form (repeat-form (- n 1) form)))) - -(defn main [] - (let [accounts [(Account.init @"alpha" 10) - (Account.init @"beta" 250)]] - (do - (IO.println &(classify (total &accounts))) - (foreach [account &accounts] - (IO.println &(Account.label account)))))) + +(defn total + [accounts] + (let-do [running 0] + (foreach [account accounts] + (set! running (+ running @(Account.balance account)))) + running)) + +(defndynamic repeat-form + [n form] + (if (= n 0) + '() + (cons form (repeat-form (- n 1) form)))) + +(defn main + [] + (let [accounts [(Account.init @"alpha" 10) (Account.init @"beta" 250)]] + (do (IO.println + &(classify (total &accounts))) + (foreach + [account &accounts] + (IO.println &(Account.label account)))))) diff --git a/tests/fixtures/corpus/clojure.clj b/tests/fixtures/corpus/clojure.clj index aebe298bf..ae13b5a55 100644 --- a/tests/fixtures/corpus/clojure.clj +++ b/tests/fixtures/corpus/clojure.clj @@ -1,13 +1,10 @@ (ns paredit.corpus "A layout corpus fixture: namespace form, maps, vectors, sets, metadata, destructuring, threading macros, and the reader shorthands." - (:require [clojure.set :as set] - [clojure.string :as str])) + (:require [clojure.set :as set] [clojure.string :as str])) (def ^:private default-options - {:retries 3 - :timeout-ms 500 - :tags #{:corpus :layout}}) + {:retries 3 :timeout-ms 500 :tags #{:corpus :layout}}) (defrecord Account [id balance]) @@ -24,11 +21,8 @@ "Move amount from one account to another, returning both." [{:keys [balance] :as from} to amount] (when (< balance amount) - (throw (ex-info "insufficient funds" - {:account (:id from) - :amount amount}))) - [(update from :balance - amount) - (update to :balance + amount)]) + (throw (ex-info "insufficient funds" {:account (:id from) :amount amount}))) + [(update from :balance - amount) (update to :balance + amount)]) (defn summarise [accounts] (let [total (reduce + (map :balance accounts)) @@ -39,13 +33,9 @@ (defmulti render :kind) -(defmethod render :text - [{:keys [body]}] - body) +(defmethod render :text [{:keys [body]}] body) -(defmethod render :default - [node] - (str "")) +(defmethod render :default [node] (str "")) (defn report [items] (doseq [item items @@ -56,11 +46,9 @@ (loop [attempt 1] (let [result (try (f) - (catch Exception _ - ::failed))] + (catch Exception _ ::failed))] (if (or (not= result ::failed) (>= attempt attempts)) result (recur (inc attempt)))))) -(defn tags-in-common [a b] - (set/intersection (:tags a #{}) (:tags b #{}))) +(defn tags-in-common [a b] (set/intersection (:tags a #{}) (:tags b #{}))) diff --git a/tests/fixtures/corpus/clos.lisp b/tests/fixtures/corpus/clos.lisp index f7b379583..75861efed 100644 --- a/tests/fixtures/corpus/clos.lisp +++ b/tests/fixtures/corpus/clos.lisp @@ -1,17 +1,27 @@ ;;;; CLOS shapes with long lambda lists and deep nesting. - (in-package #:paredit-corpus) (defclass account () ((identifier :initarg :identifier :reader account-identifier :type string) - (balance :initarg :balance :accessor account-balance :initform 0 :type integer) + (balance :initarg + :balance + :accessor + account-balance + :initform + 0 + :type + integer) (history :initarg :history :accessor account-history :initform '())) (:documentation "An account, with a deliberately long slot list.")) (defgeneric transfer (from to amount &key currency note allow-overdraft)) -(defmethod transfer ((from account) (to account) (amount integer) - &key (currency :usd) note (allow-overdraft nil)) +(defmethod transfer ((from account) (to account) + (amount integer) + &key + (currency :usd) + note + (allow-overdraft nil)) (declare (ignore currency)) (when (and (not allow-overdraft) (< (account-balance from) amount)) (error 'insufficient-funds :account from :requested amount)) @@ -28,10 +38,13 @@ (warn "transfer failed: ~a" condition) nil))) -(define-condition insufficient-funds (error) +(define-condition insufficient-funds + (error) ((account :initarg :account :reader insufficient-funds-account) (requested :initarg :requested :reader insufficient-funds-requested)) - (:report (lambda (condition stream) - (format stream "~a cannot cover ~d" - (insufficient-funds-account condition) - (insufficient-funds-requested condition))))) + (:report + (lambda (condition stream) + (format stream + "~a cannot cover ~d" + (insufficient-funds-account condition) + (insufficient-funds-requested condition))))) diff --git a/tests/fixtures/corpus/deep-nesting.lisp b/tests/fixtures/corpus/deep-nesting.lisp index 5d37b3a94..0f087f3a8 100644 --- a/tests/fixtures/corpus/deep-nesting.lisp +++ b/tests/fixtures/corpus/deep-nesting.lisp @@ -1,5 +1,4 @@ ;;;; Depth, iteration forms, and the `loop` sublanguage. - (in-package #:paredit-corpus) (defun deeply-nested (x) @@ -11,7 +10,9 @@ (if (> x 5) (if (> x 6) (if (> x 7) - (if (> x 8) :nine :eight) + (if (> x 8) + :nine + :eight) :seven) :six) :five) @@ -36,9 +37,12 @@ (let ((a 1)) (let* ((b (1+ a)) (c (* b b))) - (flet ((scale (n) (* n c))) + (flet ((scale (n) + (* n c))) (labels ((recurse (n acc) - (if (zerop n) acc (recurse (1- n) (scale acc))))) + (if (zerop n) + acc + (recurse (1- n) (scale acc))))) (multiple-value-bind (quotient remainder) (floor (recurse 3 1) 7) (destructuring-bind (&key (base 10) &allow-other-keys) '(:base 16) (list quotient remainder base)))))))) @@ -46,7 +50,14 @@ (defun resource-shapes (path) (with-open-file (stream path :direction :input :if-does-not-exist nil) (unwind-protect - (restart-case (read stream nil :eof) - (use-value (value) :report "Use a value" value) - (skip () :report "Skip the file" nil)) - (when stream (close stream))))) + (restart-case (read stream nil :eof) + (use-value (value) + :report + "Use a value" + value) + (skip () + :report + "Skip the file" + nil)) + (when stream + (close stream))))) diff --git a/tests/fixtures/corpus/elisp.el b/tests/fixtures/corpus/elisp.el index 89e619eee..7b3f94849 100644 --- a/tests/fixtures/corpus/elisp.el +++ b/tests/fixtures/corpus/elisp.el @@ -1,28 +1,32 @@ ;;; elisp.el --- Emacs Lisp corpus fixture -*- lexical-binding: t; -*- - ;;; Commentary: - ;; Emacs Lisp reader syntax that differs from Common Lisp: `?a` characters, ;; `#'` in different positions, and docstrings in every definition form. - ;;; Code: - (require 'cl-lib) -(defgroup paredit-corpus nil +(defgroup paredit-corpus + nil "A corpus fixture." - :group 'tools - :prefix "paredit-corpus-") + :group + 'tools + :prefix + "paredit-corpus-") -(defcustom paredit-corpus-delay 0.5 +(defcustom paredit-corpus-delay + 0.5 "Seconds to wait." - :type 'number - :group 'paredit-corpus) + :type + 'number + :group + 'paredit-corpus) -(defvar paredit-corpus--cache nil +(defvar paredit-corpus--cache + nil "Internal cache.") -(defconst paredit-corpus-characters (list ?\( ?\) ?\; ?\" ?\\ ?\s ?\n ?a) +(defconst paredit-corpus-characters + (list ?\( ?\) ?\; ?\" ?\\ ?\s ?\n ?a) "Characters whose reader syntax embeds delimiters.") ;;;###autoload @@ -36,7 +40,8 @@ (push item result))))) (cl-defstruct (paredit-corpus-node (:constructor paredit-corpus-node-create)) - name children) + name + children) (defun paredit-corpus-walk (node) "Walk NODE depth first." @@ -47,4 +52,5 @@ (_ (list node)))) (provide 'elisp) + ;;; elisp.el ends here diff --git a/tests/fixtures/corpus/fennel.fnl b/tests/fixtures/corpus/fennel.fnl index fc48789fb..7412a1c27 100644 --- a/tests/fixtures/corpus/fennel.fnl +++ b/tests/fixtures/corpus/fennel.fnl @@ -2,57 +2,60 @@ ;; and `var` rather than `def`, `if` as a multi-branch conditional, sequential ;; and associative table literals, `each`/`for` iteration, and the `#(...)` ;; hashfn shorthand with `$1`. - (local {: view} (require :fennel)) -(local default-options {:retries 3 - :timeout 0.5}) +(local default-options {:retries 3 :timeout 0.5}) (local double #(* 2 $1)) -(fn classify [n] - "Name the magnitude of n." - (if (< n 0) :negative - (= n 0) :zero - (> n 100) :large - :positive)) - -(fn transfer [from to amount] - (when (< from.balance amount) - (error (string.format "insufficient funds in %s" from.id))) - (set from.balance (- from.balance amount)) - (set to.balance (+ to.balance amount)) - (values from to)) - -(fn summarise [accounts] - (var total 0) - (local labels []) - (each [_ account (ipairs accounts)] - (set total (+ total account.balance)) - (when (> account.balance 0) - (table.insert labels (.. account.id ":" account.balance)))) - (.. (table.concat labels ", ") " (total " total ")")) - -(lambda retry [callback attempts] +(fn classify + [n] + "Name the magnitude of n." + (if (< n 0) + :negative + (= n 0) + :zero + (> n 100) + :large + :positive)) + +(fn transfer + [from to amount] + (when (< from.balance amount) + (error (string.format "insufficient funds in %s" from.id))) + (set from.balance (- from.balance amount)) + (set to.balance (+ to.balance amount)) + (values from to)) + +(fn summarise + [accounts] + (var total 0) + (local labels []) + (each [_ account (ipairs accounts)] + (set total (+ total account.balance)) + (when (> account.balance 0) + (table.insert labels (.. account.id ":" account.balance)))) + (.. (table.concat labels ", ") " (total " total ")")) + +(lambda retry + [callback attempts] (var result nil) (for [attempt 1 attempts] - (when (= result nil) - (let [(ok value) (pcall callback)] - (when ok - (set result value))))) + (when (= result nil) + (let [(ok value) (pcall callback)] + (when ok + (set result value))))) result) -(macro unless [condition ...] - `(when (not ,condition) - ,...)) +(macro unless + [condition ...] + `(when (not ,condition) + ,...)) -(fn report [items] - (each [_ item (ipairs items)] - (unless item.hidden - (print (view item))))) +(fn report + [items] + (each [_ item (ipairs items)] + (unless item.hidden + (print (view item))))) -{: classify - : double - : report - : summarise - : transfer} +{: classify : double : report : summarise : transfer} diff --git a/tests/fixtures/corpus/hy.hy b/tests/fixtures/corpus/hy.hy index 5524e3070..a69300d4e 100644 --- a/tests/fixtures/corpus/hy.hy +++ b/tests/fixtures/corpus/hy.hy @@ -1,56 +1,71 @@ ;; Hy: Python semantics under Lisp syntax. Flat-pair `cond`, `setv` rather ;; than `let`-heavy binding, dotted attribute access, `lfor` comprehensions, ;; and `~`/`~@` for macro unquoting. +(import json pathlib [Path]) -(import json - pathlib [Path]) +(setv DEFAULTS {"retries" 3 "timeout" 0.5}) -(setv DEFAULTS {"retries" 3 - "timeout" 0.5}) - -(defn classify [n] - "Name the magnitude of n." - (cond (< n 0) "negative" - (= n 0) "zero" - (> n 100) "large" - True "positive")) +(defn classify + [n] + "Name the magnitude of n." + (cond + (< + n + 0) + "negative" + (= + n + 0) + "zero" + (> + n + 100) + "large" + True + "positive")) (defclass Account [] - (defn __init__ [self id [balance 0]] - (setv self.id id) - (setv self.balance balance)) - - (defn transfer [self other amount] - (when (< self.balance amount) - (raise (ValueError (.format "insufficient funds in {}" self.id)))) - (-= self.balance amount) - (+= other.balance amount) - #(self other))) - -(defn summarise [accounts] - (setv total (sum (lfor account accounts account.balance))) - (setv labels (lfor account accounts - :if account.balance - (.format "{}:{}" account.id account.balance))) - (.format "{} (total {})" (.join ", " labels) total)) - -(defn load-config [path] - (with [handle (open (Path path) "r")] - (json.load handle))) - -(defn retry [callback attempts] - (for [attempt (range attempts)] - (try - (return (callback)) - (except [error RuntimeError] - (print "attempt failed:" error)))) - None) + (defn __init__ + [self id [balance 0]] + (setv self.id id) + (setv self.balance balance)) + (defn transfer + [self other amount] + (when (< self.balance amount) + (raise (ValueError (.format "insufficient funds in {}" self.id)))) + (-= self.balance amount) + (+= other.balance amount) + #(self other))) + +(defn summarise + [accounts] + (setv total (sum (lfor account accounts account.balance))) + (setv labels + (lfor account + accounts + :if + account.balance + (.format "{}:{}" account.id account.balance))) + (.format "{} (total {})" (.join ", " labels) total)) + +(defn load-config + [path] + (with [handle (open (Path path) "r")] (json.load handle))) + +(defn retry + [callback attempts] + (for [attempt (range attempts)] + (try (return (callback)) + (except [error RuntimeError] (print "attempt failed:" error)))) + None) (defmacro unless [test form] - `(when (not ~test) ~form)) + `(when (not ~test) + ~form)) -(defn main [] - (setv accounts [(Account "a" 10) (Account "b" 0)]) - (print (summarise accounts)) - (unless (get DEFAULTS "retries") - (print "no retries configured"))) +(defn main + [] + (setv accounts [(Account "a" 10) (Account "b" 0)]) + (print (summarise accounts)) + (unless (get DEFAULTS "retries") + (print "no retries configured"))) diff --git a/tests/fixtures/corpus/janet.janet b/tests/fixtures/corpus/janet.janet index d950f7154..7980c31ed 100644 --- a/tests/fixtures/corpus/janet.janet +++ b/tests/fixtures/corpus/janet.janet @@ -1,54 +1,69 @@ # Janet: `#` line comments, `@` for mutable literals, keyword keys, `|` short # function literals, `;` splicing, `~` quasiquote with `,` unquote, and a PEG # grammar as ordinary data. - (import spork/json :as json) -(def default-options - {:retries 3 - :timeout 0.5 - :tags @[:corpus :layout]}) +(def default-options {:retries 3 :timeout 0.5 :tags @[:corpus :layout]}) (defn classify - "Name the magnitude of n." - [n] - (cond - (< n 0) :negative - (= n 0) :zero - (> n 100) :large - :positive)) - -(defn transfer [from to amount] - (when (< (from :balance) amount) - (errorf "insufficient funds in %j" (from :id))) - [(merge from {:balance (- (from :balance) amount)}) - (merge to {:balance (+ (to :balance) amount)})]) - -(defn summarise [accounts] - (let [total (sum (map |($ :balance) accounts)) - labels (map (fn [account] - (string (account :id) ":" (account :balance))) + "Name the magnitude of n." + [n] + (cond + (< + n + 0) + :negative + (= + n + 0) + :zero + (> + n + 100) + :large + :positive)) + +(defn transfer + [from to amount] + (when (< (from :balance) amount) + (errorf "insufficient funds in %j" (from :id))) + [(merge from {:balance (- (from :balance) amount)}) + (merge to {:balance (+ (to :balance) amount)})]) + +(defn summarise + [accounts] + (let [total (sum (map |($ :balance) accounts)) + labels (map + (fn [account] (string (account :id) ":" (account :balance))) accounts)] - (string/join [;labels (string "total " total)] ", "))) + (string/join [;labels (string "total " total)] ", "))) (def word-grammar - (peg/compile - ~{:word (some (range "az" "AZ")) - :sep (some (set " \t")) - :main (some (+ :word :sep))})) - -(defn walk [tree] - (var acc @[]) - (each node tree - (if (indexed? node) - (array/concat acc (walk node)) - (array/push acc node))) - acc) + (peg/compile + ~{:word (some (range "az" "AZ")) + :sep + (some (set " \t")) + :main + (some (+ :word :sep))})) + +(defn walk + [tree] + (var acc @[]) + (each node + tree + (if (indexed? node) + (array/concat acc (walk node)) + (array/push acc node))) + acc) (defmacro unless [condition & body] - ~(if ,condition nil (do ,;body))) + ~(if ,condition + nil + (do ,;body))) -(defn main [& args] - (each arg args - (unless (empty? arg) - (print (classify (scan-number arg)))))) +(defn main + [& args] + (each arg + args + (unless (empty? arg) + (print (classify (scan-number arg)))))) diff --git a/tests/fixtures/corpus/lfe.lfe b/tests/fixtures/corpus/lfe.lfe index d92cb8a4d..facc33073 100644 --- a/tests/fixtures/corpus/lfe.lfe +++ b/tests/fixtures/corpus/lfe.lfe @@ -3,53 +3,52 @@ ;;;; Idiomatic LFE, not Common Lisp in an .lfe file: multi-clause `defun` ;;;; bodies, tuple literals under quasiquote, `cond` ending in `'true`, and ;;;; module-qualified calls with a colon. - (defmodule corpus - (doc "A layout corpus fixture.") - (export (start 0) - (sum 1) - (classify 1) - (summarise 1)) - (export (init 1) (handle_call 3) (handle_cast 2))) + (doc "A layout corpus fixture.") + (export (start 0) (sum 1) (classify 1) (summarise 1)) + (export (init 1) (handle_call 3) (handle_cast 2))) (defun start () "Start the server under its module name." (gen_server:start_link `#(local ,(MODULE)) (MODULE) '() '())) -(defun sum - (('()) 0) +(defun sum (('()) 0) (((cons head tail)) (+ head (sum tail)))) (defun classify (n) - (cond ((< n 0) 'negative) - ((=:= n 0) 'zero) - ((> n 100) 'large) - ('true 'positive))) + (cond + ((< n 0) 'negative) + ((=:= n 0) 'zero) + ((> n 100) 'large) + ('true 'positive))) (defun summarise (accounts) - (let* ((total (lists:foldl (lambda (account acc) (+ (element 2 account) acc)) - 0 - accounts)) - (labels (lists:map (lambda (account) - (io_lib:format "~s:~p" - (list (element 1 account) - (element 2 account)))) - accounts))) + (let* ((total + (lists:foldl + (lambda (account acc) + (+ (element 2 account) acc)) + 0 + accounts)) + (labels (lists:map + (lambda (account) + (io_lib:format "~s:~p" + (list (element 1 account) + (element 2 account)))) + accounts))) (lists:flatten (list labels (io_lib:format " (total ~p)" (list total)))))) (defun init (_args) `#(ok ,(maps:new))) -(defun handle_call - ((`#(get ,key) _from state) - `#(reply ,(maps:get key state 'undefined) ,state)) - ((`#(put ,key ,value) _from state) - `#(reply ok ,(maps:put key value state))) - ((_message _from state) - `#(reply #(error unknown) ,state))) +(defun handle_call ((`#(get ,key) _from state) + `#(reply ,(maps:get key state 'undefined) ,state)) + ((`#(put ,key ,value) _from state) `#(reply ok ,(maps:put key value state))) + ((_message _from state) `#(reply #(error unknown) ,state))) (defun handle_cast (_message state) `#(noreply ,state)) (defmacro unless (test body) - `(if ,test 'ok ,body)) + `(if ,test + 'ok + ,body)) diff --git a/tests/fixtures/corpus/racket.rkt b/tests/fixtures/corpus/racket.rkt index fcc1b672f..f80464509 100644 --- a/tests/fixtures/corpus/racket.rkt +++ b/tests/fixtures/corpus/racket.rkt @@ -1,66 +1,58 @@ #lang racket/base - ;; Racket: `#lang`, structs, keyword arguments, bracketed binding clauses, ;; `for` comprehensions, and `match`. Square brackets where Racket style uses ;; them (binding clauses and `cond` arms), parentheses everywhere else. +(require racket/list racket/match racket/string) -(require racket/list - racket/match - racket/string) - -(provide (struct-out account) - classify - summarise - transfer) +(provide (struct-out account) classify summarise transfer) (struct account (id [balance #:mutable]) #:transparent) -(define default-options - (hash 'retries 3 - 'timeout 0.5)) +(define default-options (hash 'retries 3 'timeout 0.5)) -(define (make-accounts ids) - (for/list ([id (in-list ids)]) - (account id 0))) +(define (make-accounts ids) (for/list ([id (in-list ids)]) (account id 0))) (define (classify n) - (cond - [(negative? n) 'negative] - [(zero? n) 'zero] - [(> n 100) 'large] - [else 'positive])) - -(define (transfer from to amount - #:note [note ""] - #:allow-overdraft? [overdraft? #f]) - (unless (or overdraft? (>= (account-balance from) amount)) - (error 'transfer "insufficient funds in ~a" (account-id from))) - (set-account-balance! from (- (account-balance from) amount)) - (set-account-balance! to (+ (account-balance to) amount)) - (list (account-id from) (account-id to) amount note)) + (cond + [(negative? n) 'negative] + [(zero? n) 'zero] + [(> n 100) 'large] + [else 'positive])) + +(define + (transfer from to amount #:note [note ""] #:allow-overdraft? [overdraft? #f]) + (unless (or overdraft? (>= (account-balance from) amount)) + (error 'transfer "insufficient funds in ~a" (account-id from))) + (set-account-balance! from (- (account-balance from) amount)) + (set-account-balance! to (+ (account-balance to) amount)) + (list (account-id from) (account-id to) amount note)) (define (summarise accounts) - (define total - (for/sum ([a (in-list accounts)]) - (account-balance a))) - (define labels - (for/list ([a (in-list accounts)] - #:unless (zero? (account-balance a))) - (format "~a:~a" (account-id a) (account-balance a)))) - (string-join labels ", " #:after-last (format " (total ~a)" total))) + (define total (for/sum ([a (in-list accounts)]) (account-balance a))) + (define labels + (for/list + ([a (in-list accounts)] #:unless (zero? (account-balance a))) + (format "~a:~a" (account-id a) (account-balance a)))) + (string-join labels ", " #:after-last (format " (total ~a)" total))) (define (walk tree) - (let loop ([nodes tree] - [acc '()]) - (match nodes - ['() (reverse acc)] - [(cons (? list? head) tail) (loop tail (append (walk head) acc))] - [(cons head tail) (loop tail (cons head acc))]))) + (let loop + ([nodes tree] [acc '()]) + (match nodes + ['() (reverse acc)] + [(cons (? list? head) tail) + (loop tail (append (walk head) acc))] + [(cons head tail) + (loop tail (cons head acc))]))) (define (render items) - `(ul ,@(map (lambda (item) `(li ,(format "~a" item))) items))) + `(ul + ,@(map + (lambda (item) + `(li ,(format "~a" item))) + items))) (module+ test - (require rackunit) - (check-equal? (classify -1) 'negative) - (check-equal? (walk '(1 (2 3) 4)) '(1 2 3 4))) + (require rackunit) + (check-equal? (classify -1) 'negative) + (check-equal? (walk '(1 (2 3) 4)) '(1 2 3 4))) diff --git a/tests/fixtures/corpus/reader-syntax.lisp b/tests/fixtures/corpus/reader-syntax.lisp index 2cb16a479..9e9bad275 100644 --- a/tests/fixtures/corpus/reader-syntax.lisp +++ b/tests/fixtures/corpus/reader-syntax.lisp @@ -3,33 +3,41 @@ ;;;; Every form here is legal Common Lisp. The corpus test asserts only that ;;;; parsing is lossless, formatting converges, and the tree's own paths ;;;; resolve -- not that anything in particular is understood. - (in-package #:paredit-corpus) ;;; Feature expressions. `#+`/`#-` suppress the *following form*, which means ;;; a naive reader can lose track of how many forms a file has. #+sbcl (defun implementation () :sbcl) + #-sbcl (defun implementation () :other) + #+(and sbcl (not win32)) (defun posix-only () t) + #+#.(cl:if (cl:find-package "ASDF") '(:and) '(:or)) (defun asdf-present () t) ;;; Read-time evaluation. -(defconstant +built-at-read-time+ #.(* 6 7)) +(defconstant +built-at-read-time+ + #.(* 6 7)) ;;; Circular and shared structure literals. -(defparameter *shared* '#1=(a b . #1#)) -(defparameter *pair* (list '#2=(x) '#2#)) +(defparameter *shared* + '#1=(a b . #1#)) + +(defparameter *pair* + (list '#2=(x) '#2#)) ;;; Characters whose names contain delimiters. A reader that scans for `)` ;;; without understanding `#\` closes the list here. -(defparameter *delimiters* (list #\( #\) #\" #\; #\Space #\Newline #\\)) +(defparameter *delimiters* + (list #\( #\) #\" #\; #\Space #\Newline #\\)) ;;; Block comments, including nested ones. #| (this is not code) #| and this is a nested block comment |# |# -(defun after-block-comment () :ok) +(defun after-block-comment () + :ok) ;;; Strings containing everything that looks like structure. (defparameter *tricky-strings* @@ -38,13 +46,21 @@ multi-line string")) ;;; Vertical-bar symbols: the delimiters inside are part of the name. -(defun |weird name with (parens) and ;semicolons| () :ok) -(defparameter |a| '|b c|) +(defun |weird name with (parens) and ;semicolons| () + :ok) + +(defparameter |a| + '|b c|) ;;; Vectors, bit vectors, and pathnames. -(defparameter *vector* #(1 2 3)) -(defparameter *bits* #*10110) -(defparameter *path* #p"/tmp/corpus.lisp") +(defparameter *vector* + #(1 2 3)) + +(defparameter *bits* + #*10110) + +(defparameter *path* + #p"/tmp/corpus.lisp") ;;; Quasiquotation nested two deep. (defmacro nested-template (name) @@ -52,13 +68,25 @@ string")) `(list ',inner ,@(list 1 2 3)))) ;;; Dotted pairs and the empty list. -(defparameter *dotted* '(a . b)) -(defparameter *nothing* '()) +(defparameter *dotted* + '(a . b)) + +(defparameter *nothing* + '()) ;;; Numeric literal dispatches. `#c` is CLHS 2.4.8.11 and was the one ANSI ;;; dispatch this reader did not know until a Quicklisp corpus run found it. -(defparameter *complex* (list #C(0.0 0.0) #C(1.5 -2.0) #c(1/2 3/4))) -(defparameter *radix* (list #b1011 #o755 #xdeadBEEF #16r1F #2r1010)) -(defparameter *array* #2A((1 2 3) (4 5 6))) -(defparameter *struct* #S(paredit-corpus-point :x 1 :y 2)) -(defparameter *ratio* (list 1/3 -22/7)) +(defparameter *complex* + (list #C(0.0 0.0) #C(1.5 -2.0) #c(1/2 3/4))) + +(defparameter *radix* + (list #b1011 #o755 #xdeadBEEF #16r1F #2r1010)) + +(defparameter *array* + #2A((1 2 3) (4 5 6))) + +(defparameter *struct* + #S(paredit-corpus-point :x 1 :y 2)) + +(defparameter *ratio* + (list 1/3 -22/7)) diff --git a/tests/fixtures/corpus/scheme.scm b/tests/fixtures/corpus/scheme.scm index 05aac36bb..cf03dbb62 100644 --- a/tests/fixtures/corpus/scheme.scm +++ b/tests/fixtures/corpus/scheme.scm @@ -1,5 +1,4 @@ ;;;; Scheme shapes: define-values, named let, syntax-rules, and block comments. - (define-library (paredit corpus) (export walk fold-tree) (import (scheme base) (scheme write)) diff --git a/tests/fixtures/lint_golden/broad.lisp b/tests/fixtures/lint_golden/broad.lisp index d02ff4496..d61dbc403 100644 --- a/tests/fixtures/lint_golden/broad.lisp +++ b/tests/fixtures/lint_golden/broad.lisp @@ -2,142 +2,378 @@ ;; golden text/json/sarif/fix-plan/fix outputs pin today's behavior for every ;; rule at once. Each line is independent and self-contained; forms are not ;; meant to be loaded/evaluated, only parsed and linted. - ;; --- fixable rules (mirrors the fixable_rules_match_the_fix_engine guard ;; --- test in src/presentation/cli/lint_report/workflow.rs) --- -(list '5) ; redundant-quote -(progn only) ; redundant-progn -(progn a (progn b c)) ; nested-progn (the inner progn) -(when q (progn s t)) ; redundant-body-progn -(let () (ela) (elb)) ; empty-let -(if c d nil) ; redundant-if-nil -(funcall #'g m) ; redundant-funcall -(the t whatever) ; redundant-the -(funcall (lambda (fx) fx) 9) ; funcall-lambda -(mapcar #'(lambda (sq) sq) sqs) ; sharp-quoted-lambda -(identity h) ; redundant-identity -(cons e nil) ; cons-to-list -(reverse (reverse dr)) ; double-reverse -(append (list al) ar) ; append-list-to-cons -(format nil "~A" fs) ; format-to-string -(format t "~%") ; format-newline -(floor fq 1) ; redundant-divisor -(- 0 amt) ; verbose-negation -(list* la lb) ; list-star-to-cons -(values-list (list va vb)) ; values-list-of-list -(prog1 (p1x)) ; redundant-prog1 -(subseq sz 0) ; subseq-zero -(car (nthcdr cn cx)) ; car-nthcdr -(car (reverse crx)) ; car-reverse -(append anx nil) ; append-nil -(multiple-value-list (values mva mvb)) ; multiple-value-list-of-values -(typep tpx 'string) ; typep-predicate -(coerce ctx t) ; coerce-to-t -(gethash gdk gdh nil) ; gethash-default -(make-hash-table :test 'eql) ; make-hash-table-test -(let* ((a 1)) a) ; redundant-let-star -(cond (ok (run))) ; single-clause-cond -(cond (t (r1) (r2))) ; cond-t-clause -(incf tally 1) ; explicit-step-delta -(incf nsd -3) ; negated-step-delta -(return-from blk nil) ; explicit-nil-return -(multiple-value-bind (mv) (vals) mv) ; single-value-bind -(or za (or pb qc)) ; nested-boolean -(when wa (when wb (wc))) ; nested-when -(unless ua (unless ub (uc))) ; nested-unless -(and x) ; single-operand-boolean -(append solo) ; single-operand-list-op -(* x) ; single-operand-arithmetic -(when (not r) y) ; negated-when-unless -(if p q) ; one-armed-if -(setf ctr (1+ ctr)) ; manual-incf -(setf lst (cons e lst)) ; manual-push -(setf st (adjoin e st)) ; manual-pushnew -(car (cdr z)) ; nested-cxr -(nth 0 zs) ; nth-constant-index -(nthcdr 0 nz) ; nthcdr-zero -(nthcdr 2 ns) ; nthcdr-small-index -(apply #'g (list m)) ; redundant-apply -(find ret lst :test #'eql) ; redundant-eql-test -(find rsz lst :start 0) ; redundant-start-zero -(find ren lst :end nil) ; redundant-end-nil -(find rfe lst :from-end nil) ; redundant-from-end-nil -(remove rcn lst :count nil) ; redundant-count-nil +(list '5) ; redundant-quote + +(progn + only) ; redundant-progn + +(progn + a + (progn + b + c)) ; nested-progn (the inner progn) + +(when q + (progn + s + t)) ; redundant-body-progn + +(let () + (ela) + (elb)) ; empty-let + +(if c + d + nil) ; redundant-if-nil + +(funcall #'g m) ; redundant-funcall + +(the t whatever) ; redundant-the + +(funcall + (lambda (fx) + fx) + 9) ; funcall-lambda + +(mapcar + #'(lambda (sq) + sq) + sqs) ; sharp-quoted-lambda + +(identity h) ; redundant-identity + +(cons e nil) ; cons-to-list + +(reverse (reverse dr)) ; double-reverse + +(append (list al) ar) ; append-list-to-cons + +(format nil "~A" fs) ; format-to-string + +(format t "~%") ; format-newline + +(floor fq 1) ; redundant-divisor + +(- 0 amt) ; verbose-negation + +(list* la lb) ; list-star-to-cons + +(values-list (list va vb)) ; values-list-of-list + +(prog1 + (p1x)) ; redundant-prog1 + +(subseq sz 0) ; subseq-zero + +(car (nthcdr cn cx)) ; car-nthcdr + +(car (reverse crx)) ; car-reverse + +(append anx nil) ; append-nil + +(multiple-value-list (values mva mvb)) ; multiple-value-list-of-values + +(typep tpx 'string) ; typep-predicate + +(coerce ctx t) ; coerce-to-t + +(gethash gdk gdh nil) ; gethash-default + +(make-hash-table :test 'eql) ; make-hash-table-test + +(let* ((a 1)) + a) ; redundant-let-star + +(cond + (ok (run))) ; single-clause-cond + +(cond + (t + (r1) + (r2))) ; cond-t-clause + +(incf tally 1) ; explicit-step-delta + +(incf nsd -3) ; negated-step-delta + +(return-from blk + nil) ; explicit-nil-return + +(multiple-value-bind (mv) (vals) + mv) ; single-value-bind + +(or za (or pb qc)) ; nested-boolean + +(when wa + (when wb + (wc))) ; nested-when + +(unless ua + (unless ub + (uc))) ; nested-unless + +(and x) ; single-operand-boolean + +(append solo) ; single-operand-list-op + +(* x) ; single-operand-arithmetic + +(when (not r) + y) ; negated-when-unless + +(if p + q) ; one-armed-if + +(setf ctr (1+ ctr)) ; manual-incf + +(setf lst (cons e lst)) ; manual-push + +(setf st (adjoin e st)) ; manual-pushnew + +(car (cdr z)) ; nested-cxr + +(nth 0 zs) ; nth-constant-index + +(nthcdr 0 nz) ; nthcdr-zero + +(nthcdr 2 ns) ; nthcdr-small-index + +(apply #'g (list m)) ; redundant-apply + +(find ret lst :test #'eql) ; redundant-eql-test + +(find rsz lst :start 0) ; redundant-start-zero + +(find ren lst :end nil) ; redundant-end-nil + +(find rfe lst :from-end nil) ; redundant-from-end-nil + +(remove rcn lst :count nil) ; redundant-count-nil + (string= (string-downcase sa) (string-downcase sb)) ; string-case-fold -(char= (char-downcase ca) (char-downcase cb)) ; char-case-fold -(string-upcase (string-downcase nsc)) ; nested-string-case -(code-char (char-code ccc)) ; code-char-char-code -(last ldc 1) ; last-default-count -(butlast bdc 1) ; butlast-default-count -(make-list mde :initial-element nil) ; make-list-default-element -(parse-integer pir :radix 10) ; parse-integer-default-radix -(getf gdn :key nil) ; getf-default-nil -(make-array madk :adjustable nil) ; make-array-default-keyword -(char-upcase (char-downcase ncc)) ; nested-char-case -(list* lsn1 lsn2 nil) ; list-star-nil -(sort rik #'< :key #'identity) ; redundant-identity-key -(= tally 0) ; sign-comparison -(not (< a b)) ; negated-comparison -(if (not c) a b) ; negated-if -(if iv iv jv) ; if-to-or -(if iw nil t) ; if-not -(if iu nil (iue)) ; if-to-unless -(prog2 (p2a) (p2b)) ; prog2-to-progn -(handler-case (hcx)) ; handler-case-no-clauses -(unwind-protect (upx)) ; unwind-protect-no-cleanup -(+ osa 1) ; one-step-arithmetic -(if t on off) ; constant-if-test -(when t (bd)) ; constant-when-test -(and p t q) ; redundant-boolean-identity -(and (not p) (not q)) ; de-morgan -(equal w nil) ; nil-comparison -(eq n 7) ; eq-number-comparison -(eq c #\a) ; eq-char-comparison -(if a b c d) ; if-arity (NOT fixable) + +(char= (char-downcase ca) (char-downcase cb)) ; char-case-fold + +(string-upcase (string-downcase nsc)) ; nested-string-case + +(code-char (char-code ccc)) ; code-char-char-code + +(last ldc 1) ; last-default-count + +(butlast bdc 1) ; butlast-default-count + +(make-list mde :initial-element nil) ; make-list-default-element + +(parse-integer pir :radix 10) ; parse-integer-default-radix + +(getf gdn :key nil) ; getf-default-nil + +(make-array madk :adjustable nil) ; make-array-default-keyword + +(char-upcase (char-downcase ncc)) ; nested-char-case + +(list* lsn1 lsn2 nil) ; list-star-nil + +(sort rik #'< :key #'identity) ; redundant-identity-key + +(= tally 0) ; sign-comparison + +(not (< a b)) ; negated-comparison + +(if (not c) + a + b) ; negated-if + +(if iv + iv + jv) ; if-to-or + +(if iw + nil + t) ; if-not + +(if iu + nil + (iue)) ; if-to-unless + +(prog2 + (p2a) + (p2b)) ; prog2-to-progn + +(handler-case (hcx)) ; handler-case-no-clauses + +(unwind-protect (upx)) ; unwind-protect-no-cleanup + +(+ osa 1) ; one-step-arithmetic + +(if t + on + off) ; constant-if-test + +(when t + (bd)) ; constant-when-test + +(and p t q) ; redundant-boolean-identity + +(and (not p) (not q)) ; de-morgan + +(equal w nil) ; nil-comparison + +(eq n 7) ; eq-number-comparison + +(eq c #\a) ; eq-char-comparison + +(if a + b + c + d) ; if-arity (NOT fixable) ;; --- report-only rules (no auto-fix), one form per rule --- -(setq x x) ; self-assignment -(defun reset () (setf total 0 total 1)) ; duplicate-setf-places -(setf (slot a) 1 (slot b)) ; setf-arity -(setq (car x) 5) ; setq-non-variable -(incf counter 1 2) ; modify-macro-arity -(defun scale (factor x factor) (* factor x)) ; duplicate-parameters -(defun dupkw (&optional x &optional y) x) ; duplicate-lambda-list-keyword -(defun kworder (&key a &optional b) a) ; lambda-list-keyword-order -(when (eq status status) 1) ; self-comparison -(defun ready? (x) (eq (compute x) t)) ; t-comparison -(if test (foo x) (foo x)) ; identical-if-branches -(the fixnum) ; the-arity -(eq x) ; equality-arity -(gethash key) ; accessor-arity -(case x (:a 1) (:b 2) (:a 3)) ; duplicate-case-keys -(case sym ('apple :fruit) ('carrot :veg) (t :x)) ; quoted-case-key -(case x (nil 1) (t 2)) ; case-nil-key -(typecase x (nil 1) (t 2)) ; typecase-nil-key -(case x (1 :one) 2 :two) ; malformed-case-clause -(case x (1 :one) (t :def) (2 :two)) ; unreachable-case-clause -(ecase x (1 :one) (t :default)) ; exhaustive-case-otherwise -(cond ((foo) 1) ((bar) 2) ((foo) 3)) ; duplicate-cond-tests -(cond ((foo) 1) (t 2) ((bar) 3)) ; unreachable-cond-clause -(cond ((plusp x) :pos) ((minusp x) :neg) :zero) ; malformed-cond-clause -(let ((x 1) (y 2) (x 3)) x) ; duplicate-let-bindings -(let ((x 1 y 2)) (+ x y)) ; malformed-let-binding -(let ((nil 1) (:status :ok)) :status) ; binds-constant -(dolist (x) (print x)) ; malformed-iteration-spec -(eval-when (:compile-toplevel :executee) 1) ; eval-when-situation -(or x y x) ; duplicate-boolean-operands -(and (ready a) nil (finalize b)) ; dead-boolean-operand -(when (eql name "root") 1) ; eql-string-comparison -(when (eql p '(:a :b)) 1) ; eql-list-comparison -(defun eqlsearch (items) (member "x" items)) ; eql-search-literal -(defun singlearg (x) (when (< x) (go))) ; single-arg-comparison -(defun missingdest (x) (format "~a~%" x)) ; format-missing-destination -(defun litplace () (incf 5)) ; literal-place -(defun destrlit () (nreverse '(a b c))) ; destructive-literal -(defun charopstr (c) (when (char= c "a") :hit)) ; char-op-string -(defun emptybody (ready) (when ready)) ; empty-body -(defun identarith (x) (+ x 0)) ; identity-arithmetic -(/ x 0) ; zero-divisor -(make-instance 'c :x 1 :x 2) ; duplicate-keyword -(defpackage :app (:export 'foo)) ; defpackage-quoted -(incf counter 0) ; step-zero +(setq x x) ; self-assignment + +(defun reset () + (setf total 0 + total 1)) ; duplicate-setf-places + +(setf (slot a) 1 + (slot b)) ; setf-arity + +(setq (car x) 5) ; setq-non-variable + +(incf counter 1 2) ; modify-macro-arity + +(defun scale (factor x factor) + (* factor x)) ; duplicate-parameters + +(defun dupkw (&optional x &optional y) + x) ; duplicate-lambda-list-keyword + +(defun kworder (&key a &optional b) + a) ; lambda-list-keyword-order + +(when (eq status status) + 1) ; self-comparison + +(defun ready? (x) + (eq (compute x) t)) ; t-comparison + +(if test + (foo x) + (foo x)) ; identical-if-branches + +(the fixnum) ; the-arity + +(eq x) ; equality-arity + +(gethash key) ; accessor-arity + +(case x + (:a 1) + (:b 2) + (:a 3)) ; duplicate-case-keys + +(case sym + ('apple :fruit) + ('carrot :veg) + (t :x)) ; quoted-case-key + +(case x + (nil 1) + (t 2)) ; case-nil-key + +(typecase x + (nil 1) + (t 2)) ; typecase-nil-key + +(case x + (1 :one) + 2 + :two) ; malformed-case-clause + +(case x + (1 :one) + (t :def) + (2 :two)) ; unreachable-case-clause + +(ecase x + (1 :one) + (t :default)) ; exhaustive-case-otherwise + +(cond + ((foo) 1) + ((bar) 2) + ((foo) 3)) ; duplicate-cond-tests + +(cond + ((foo) 1) + (t 2) + ((bar) 3)) ; unreachable-cond-clause + +(cond + ((plusp x) :pos) + ((minusp x) :neg) + :zero) ; malformed-cond-clause + +(let ((x 1) + (y 2) + (x 3)) + x) ; duplicate-let-bindings + +(let ((x 1 y 2)) + (+ x y)) ; malformed-let-binding + +(let ((nil 1) + (:status :ok)) + :status) ; binds-constant + +(dolist (x) + (print x)) ; malformed-iteration-spec + +(eval-when (:compile-toplevel :executee) + 1) ; eval-when-situation + +(or x y x) ; duplicate-boolean-operands + +(and (ready a) nil (finalize b)) ; dead-boolean-operand + +(when (eql name "root") + 1) ; eql-string-comparison + +(when (eql p '(:a :b)) + 1) ; eql-list-comparison + +(defun eqlsearch (items) + (member "x" items)) ; eql-search-literal + +(defun singlearg (x) + (when (< x) + (go))) ; single-arg-comparison + +(defun missingdest (x) + (format "~a~%" x)) ; format-missing-destination + +(defun litplace () + (incf 5)) ; literal-place + +(defun destrlit () + (nreverse '(a b c))) ; destructive-literal + +(defun charopstr (c) + (when (char= c "a") + :hit)) ; char-op-string + +(defun emptybody (ready) + (when ready)) ; empty-body + +(defun identarith (x) + (+ x 0)) ; identity-arithmetic + +(/ x 0) ; zero-divisor + +(make-instance 'c :x 1 :x 2) ; duplicate-keyword + +(defpackage :app (:export 'foo)) ; defpackage-quoted + +(incf counter 0) ; step-zero diff --git a/tests/fixtures/lint_golden/emacs-lisp.el b/tests/fixtures/lint_golden/emacs-lisp.el index 034565216..c87a6693f 100644 --- a/tests/fixtures/lint_golden/emacs-lisp.el +++ b/tests/fixtures/lint_golden/emacs-lisp.el @@ -1,10 +1,9 @@ ;;; emacs-lisp.el --- fixture for the Emacs Lisp lint rules - ;; Every rule in `paredit-feature-lint-emacs-lisp` fires here. Line 1 ;; deliberately carries no lexical setting, and the Local Variables block at ;; the end puts one where Emacs will never look for it. - -(defcustom fixture-option nil +(defcustom fixture-option + nil "An option with neither a type nor a group.") (defmacro fixture-macro (n) @@ -14,11 +13,13 @@ (defun fixture-loop () "Use a cl.el name Emacs 27.1 removed." - (loop for n from 1 to 3 collect n)) + (loop for n from 1 to 3 + collect n)) (defun fixture-quoted-lambda () "Return a list that looks like a function." - '(lambda (n) n)) + '(lambda (n) + n)) (defun fixture-condition-case () "Catch nothing at all." @@ -36,5 +37,4 @@ ;; lexical-binding: t ;; End: ;;; emacs-lisp.el ends here - ;;;###autoload diff --git a/tests/fixtures/lint_golden/expected/broad.fixed.source.golden b/tests/fixtures/lint_golden/expected/broad.fixed.source.golden index 943611f48..e14caf684 100644 --- a/tests/fixtures/lint_golden/expected/broad.fixed.source.golden +++ b/tests/fixtures/lint_golden/expected/broad.fixed.source.golden @@ -2,142 +2,352 @@ ;; golden text/json/sarif/fix-plan/fix outputs pin today's behavior for every ;; rule at once. Each line is independent and self-contained; forms are not ;; meant to be loaded/evaluated, only parsed and linted. - ;; --- fixable rules (mirrors the fixable_rules_match_the_fix_engine guard ;; --- test in src/presentation/cli/lint_report/workflow.rs) --- -(list 5) ; redundant-quote -only ; redundant-progn -(progn a b c) ; nested-progn (the inner progn) -(when q s t) ; redundant-body-progn -(progn (ela) (elb)) ; empty-let -(when c d) ; redundant-if-nil -(g m) ; redundant-funcall -whatever ; redundant-the -((lambda (fx) fx) 9) ; funcall-lambda -(mapcar (lambda (sq) sq) sqs) ; sharp-quoted-lambda -h ; redundant-identity -(list e) ; cons-to-list -(copy-seq dr) ; double-reverse -(cons al ar) ; append-list-to-cons -(princ-to-string fs) ; format-to-string -(terpri) ; format-newline -(floor fq) ; redundant-divisor -(- amt) ; verbose-negation -(cons la lb) ; list-star-to-cons -(values va vb) ; values-list-of-list -(p1x) ; redundant-prog1 -(copy-seq sz) ; subseq-zero -(nth cn cx) ; car-nthcdr -(car (last crx)) ; car-reverse -(copy-list anx) ; append-nil -(list mva mvb) ; multiple-value-list-of-values -(stringp tpx) ; typep-predicate -ctx ; coerce-to-t -(gethash gdk gdh) ; gethash-default -(make-hash-table) ; make-hash-table-test -(let ((a 1)) a) ; redundant-let-star -(when ok (run)) ; single-clause-cond -(progn (r1) (r2)) ; cond-t-clause -(incf tally) ; explicit-step-delta -(decf nsd 3) ; negated-step-delta -(return-from blk) ; explicit-nil-return -(let ((mv (vals))) mv) ; single-value-bind -(or za pb qc) ; nested-boolean -(when (and wa wb) (wc)) ; nested-when -(unless (or ua ub) (uc)) ; nested-unless -x ; single-operand-boolean -solo ; single-operand-list-op -x ; single-operand-arithmetic -(unless r y) ; negated-when-unless -(when p q) ; one-armed-if -(incf ctr) ; manual-incf -(push e lst) ; manual-push -(pushnew e st) ; manual-pushnew -(cadr z) ; nested-cxr -(first zs) ; nth-constant-index -nz ; nthcdr-zero -(cddr ns) ; nthcdr-small-index -(g m) ; redundant-apply -(find ret lst) ; redundant-eql-test -(find rsz lst) ; redundant-start-zero -(find ren lst) ; redundant-end-nil -(find rfe lst) ; redundant-from-end-nil -(remove rcn lst) ; redundant-count-nil +(list 5) ; redundant-quote + +only ; redundant-progn + +(progn + a + b + c) ; nested-progn (the inner progn) + +(when q + s + t) ; redundant-body-progn + +(progn + (ela) + (elb)) ; empty-let + +(when c + d) ; redundant-if-nil + +(g m) ; redundant-funcall + +whatever ; redundant-the + +((lambda (fx) + fx) + 9) ; funcall-lambda + +(mapcar + (lambda (sq) + sq) + sqs) ; sharp-quoted-lambda + +h ; redundant-identity + +(list e) ; cons-to-list + +(copy-seq dr) ; double-reverse + +(cons al ar) ; append-list-to-cons + +(princ-to-string fs) ; format-to-string + +(terpri) ; format-newline + +(floor fq) ; redundant-divisor + +(- amt) ; verbose-negation + +(cons la lb) ; list-star-to-cons + +(values va vb) ; values-list-of-list + +(p1x) ; redundant-prog1 + +(copy-seq sz) ; subseq-zero + +(nth cn cx) ; car-nthcdr + +(car (last crx)) ; car-reverse + +(copy-list anx) ; append-nil + +(list mva mvb) ; multiple-value-list-of-values + +(stringp tpx) ; typep-predicate + +ctx ; coerce-to-t + +(gethash gdk gdh) ; gethash-default + +(make-hash-table) ; make-hash-table-test + +(let ((a 1)) + a) ; redundant-let-star + +(when ok (run)) ; single-clause-cond + +(progn (r1) + (r2)) ; cond-t-clause + +(incf tally) ; explicit-step-delta + +(decf nsd 3) ; negated-step-delta + +(return-from blk) ; explicit-nil-return + +(let ((mv (vals))) mv) ; single-value-bind + +(or za pb qc) ; nested-boolean + +(when (and wa wb) (wc)) ; nested-when + +(unless (or ua ub) (uc)) ; nested-unless + +x ; single-operand-boolean + +solo ; single-operand-list-op + +x ; single-operand-arithmetic + +(unless r + y) ; negated-when-unless + +(when p + q) ; one-armed-if + +(incf ctr) ; manual-incf + +(push e lst) ; manual-push + +(pushnew e st) ; manual-pushnew + +(cadr z) ; nested-cxr + +(first zs) ; nth-constant-index + +nz ; nthcdr-zero + +(cddr ns) ; nthcdr-small-index + +(g m) ; redundant-apply + +(find ret lst) ; redundant-eql-test + +(find rsz lst) ; redundant-start-zero + +(find ren lst) ; redundant-end-nil + +(find rfe lst) ; redundant-from-end-nil + +(remove rcn lst) ; redundant-count-nil + (string-equal sa sb) ; string-case-fold -(char-equal ca cb) ; char-case-fold -(string-upcase nsc) ; nested-string-case -ccc ; code-char-char-code -(last ldc) ; last-default-count -(butlast bdc) ; butlast-default-count -(make-list mde) ; make-list-default-element -(parse-integer pir) ; parse-integer-default-radix -(getf gdn :key) ; getf-default-nil -(make-array madk) ; make-array-default-keyword -(char-upcase ncc) ; nested-char-case -(list lsn1 lsn2) ; list-star-nil -(sort rik #'<) ; redundant-identity-key -(zerop tally) ; sign-comparison -(>= a b) ; negated-comparison -(if c b a) ; negated-if -(or iv jv) ; if-to-or -(not iw) ; if-not -(unless iu (iue)) ; if-to-unless -(progn (p2a) (p2b)) ; prog2-to-progn -(hcx) ; handler-case-no-clauses -(upx) ; unwind-protect-no-cleanup -(1+ osa) ; one-step-arithmetic -on ; constant-if-test -(bd) ; constant-when-test -(and p q) ; redundant-boolean-identity -(not (or p q)) ; de-morgan -(null w) ; nil-comparison -(eql n 7) ; eq-number-comparison -(eql c #\a) ; eq-char-comparison -(if a b c d) ; if-arity (NOT fixable) + +(char-equal ca cb) ; char-case-fold + +(string-upcase nsc) ; nested-string-case + +ccc ; code-char-char-code + +(last ldc) ; last-default-count + +(butlast bdc) ; butlast-default-count + +(make-list mde) ; make-list-default-element + +(parse-integer pir) ; parse-integer-default-radix + +(getf gdn :key) ; getf-default-nil + +(make-array madk) ; make-array-default-keyword + +(char-upcase ncc) ; nested-char-case + +(list lsn1 lsn2) ; list-star-nil + +(sort rik #'<) ; redundant-identity-key + +(zerop tally) ; sign-comparison + +(>= a b) ; negated-comparison + +(if c b a) ; negated-if + +(or iv jv) ; if-to-or + +(not iw) ; if-not + +(unless iu (iue)) ; if-to-unless + +(progn + (p2a) + (p2b)) ; prog2-to-progn + +(hcx) ; handler-case-no-clauses + +(upx) ; unwind-protect-no-cleanup + +(1+ osa) ; one-step-arithmetic + +on ; constant-if-test + +(bd) ; constant-when-test + +(and p q) ; redundant-boolean-identity + +(not (or p q)) ; de-morgan + +(null w) ; nil-comparison + +(eql n 7) ; eq-number-comparison + +(eql c #\a) ; eq-char-comparison + +(if a + b + c + d) ; if-arity (NOT fixable) ;; --- report-only rules (no auto-fix), one form per rule --- -(setq x x) ; self-assignment -(defun reset () (setf total 0 total 1)) ; duplicate-setf-places -(setf (slot a) 1 (slot b)) ; setf-arity -(setq (car x) 5) ; setq-non-variable -(incf counter 1 2) ; modify-macro-arity -(defun scale (factor x factor) (* factor x)) ; duplicate-parameters -(defun dupkw (&optional x &optional y) x) ; duplicate-lambda-list-keyword -(defun kworder (&key a &optional b) a) ; lambda-list-keyword-order -(when (eq status status) 1) ; self-comparison -(defun ready? (x) (eq (compute x) t)) ; t-comparison -(if test (foo x) (foo x)) ; identical-if-branches -(the fixnum) ; the-arity -(eq x) ; equality-arity -(gethash key) ; accessor-arity -(case x (:a 1) (:b 2) (:a 3)) ; duplicate-case-keys -(case sym ('apple :fruit) ('carrot :veg) (t :x)) ; quoted-case-key -(case x (nil 1) (t 2)) ; case-nil-key -(typecase x (nil 1) (t 2)) ; typecase-nil-key -(case x (1 :one) 2 :two) ; malformed-case-clause -(case x (1 :one) (t :def) (2 :two)) ; unreachable-case-clause -(ecase x (1 :one) (t :default)) ; exhaustive-case-otherwise -(cond ((foo) 1) ((bar) 2) ((foo) 3)) ; duplicate-cond-tests -(cond ((foo) 1) (t 2) ((bar) 3)) ; unreachable-cond-clause -(cond ((plusp x) :pos) ((minusp x) :neg) :zero) ; malformed-cond-clause -(let ((x 1) (y 2) (x 3)) x) ; duplicate-let-bindings -(let ((x 1 y 2)) (+ x y)) ; malformed-let-binding -(let ((nil 1) (:status :ok)) :status) ; binds-constant -(dolist (x) (print x)) ; malformed-iteration-spec -(eval-when (:compile-toplevel :executee) 1) ; eval-when-situation -(or x y x) ; duplicate-boolean-operands -(and (ready a) nil (finalize b)) ; dead-boolean-operand -(when (eql name "root") 1) ; eql-string-comparison -(when (eql p '(:a :b)) 1) ; eql-list-comparison -(defun eqlsearch (items) (member "x" items)) ; eql-search-literal -(defun singlearg (x) (when (< x) (go))) ; single-arg-comparison -(defun missingdest (x) (format "~a~%" x)) ; format-missing-destination -(defun litplace () (incf 5)) ; literal-place -(defun destrlit () (nreverse '(a b c))) ; destructive-literal -(defun charopstr (c) (when (char= c "a") :hit)) ; char-op-string -(defun emptybody (ready) (when ready)) ; empty-body -(defun identarith (x) (+ x 0)) ; identity-arithmetic -(/ x 0) ; zero-divisor -(make-instance 'c :x 1 :x 2) ; duplicate-keyword -(defpackage :app (:export 'foo)) ; defpackage-quoted -(incf counter 0) ; step-zero +(setq x x) ; self-assignment + +(defun reset () + (setf total 0 + total 1)) ; duplicate-setf-places + +(setf (slot a) 1 + (slot b)) ; setf-arity + +(setq (car x) 5) ; setq-non-variable + +(incf counter 1 2) ; modify-macro-arity + +(defun scale (factor x factor) + (* factor x)) ; duplicate-parameters + +(defun dupkw (&optional x &optional y) + x) ; duplicate-lambda-list-keyword + +(defun kworder (&key a &optional b) + a) ; lambda-list-keyword-order + +(when (eq status status) + 1) ; self-comparison + +(defun ready? (x) + (eq (compute x) t)) ; t-comparison + +(if test + (foo x) + (foo x)) ; identical-if-branches + +(the fixnum) ; the-arity + +(eq x) ; equality-arity + +(gethash key) ; accessor-arity + +(case x + (:a 1) + (:b 2) + (:a 3)) ; duplicate-case-keys + +(case sym + ('apple :fruit) + ('carrot :veg) + (t :x)) ; quoted-case-key + +(case x + (nil 1) + (t 2)) ; case-nil-key + +(typecase x + (nil 1) + (t 2)) ; typecase-nil-key + +(case x + (1 :one) + 2 + :two) ; malformed-case-clause + +(case x + (1 :one) + (t :def) + (2 :two)) ; unreachable-case-clause + +(ecase x + (1 :one) + (t :default)) ; exhaustive-case-otherwise + +(cond + ((foo) 1) + ((bar) 2) + ((foo) 3)) ; duplicate-cond-tests + +(cond + ((foo) 1) + (t 2) + ((bar) 3)) ; unreachable-cond-clause + +(cond + ((plusp x) :pos) + ((minusp x) :neg) + :zero) ; malformed-cond-clause + +(let ((x 1) + (y 2) + (x 3)) + x) ; duplicate-let-bindings + +(let ((x 1 y 2)) + (+ x y)) ; malformed-let-binding + +(let ((nil 1) + (:status :ok)) + :status) ; binds-constant + +(dolist (x) + (print x)) ; malformed-iteration-spec + +(eval-when (:compile-toplevel :executee) + 1) ; eval-when-situation + +(or x y x) ; duplicate-boolean-operands + +(and (ready a) nil (finalize b)) ; dead-boolean-operand + +(when (eql name "root") + 1) ; eql-string-comparison + +(when (eql p '(:a :b)) + 1) ; eql-list-comparison + +(defun eqlsearch (items) + (member "x" items)) ; eql-search-literal + +(defun singlearg (x) + (when (< x) + (go))) ; single-arg-comparison + +(defun missingdest (x) + (format "~a~%" x)) ; format-missing-destination + +(defun litplace () + (incf 5)) ; literal-place + +(defun destrlit () + (nreverse '(a b c))) ; destructive-literal + +(defun charopstr (c) + (when (char= c "a") + :hit)) ; char-op-string + +(defun emptybody (ready) + (when ready)) ; empty-body + +(defun identarith (x) + (+ x 0)) ; identity-arithmetic + +(/ x 0) ; zero-divisor + +(make-instance 'c :x 1 :x 2) ; duplicate-keyword + +(defpackage :app (:export 'foo)) ; defpackage-quoted + +(incf counter 0) ; step-zero diff --git a/tests/fixtures/lint_golden/expected/broad.fixplan.json.golden b/tests/fixtures/lint_golden/expected/broad.fixplan.json.golden index e5cf219cd..932b18edd 100644 --- a/tests/fixtures/lint_golden/expected/broad.fixplan.json.golden +++ b/tests/fixtures/lint_golden/expected/broad.fixplan.json.golden @@ -8,14 +8,14 @@ "replacements": [ { "byte_length": 19, - "byte_offset": 3644, + "byte_offset": 2282, "text": "(incf ctr)" } ], "rule": "manual-incf", "span": { - "end": 3663, - "start": 3644 + "end": 2301, + "start": 2282 } }, { @@ -25,14 +25,14 @@ "replacements": [ { "byte_length": 23, - "byte_offset": 3710, + "byte_offset": 2317, "text": "(push e lst)" } ], "rule": "manual-push", "span": { - "end": 3733, - "start": 3710 + "end": 2340, + "start": 2317 } }, { @@ -42,14 +42,14 @@ "replacements": [ { "byte_length": 23, - "byte_offset": 3776, + "byte_offset": 2356, "text": "(pushnew e st)" } ], "rule": "manual-pushnew", "span": { - "end": 3799, - "start": 3776 + "end": 2379, + "start": 2356 } }, { @@ -59,14 +59,14 @@ "replacements": [ { "byte_length": 14, - "byte_offset": 2773, + "byte_offset": 1786, "text": "(incf tally)" } ], "rule": "explicit-step-delta", "span": { - "end": 2787, - "start": 2773 + "end": 1800, + "start": 1786 } }, { @@ -76,14 +76,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 2847, + "byte_offset": 1824, "text": "(decf nsd 3)" } ], "rule": "negated-step-delta", "span": { - "end": 2860, - "start": 2847 + "end": 1837, + "start": 1824 } }, { @@ -92,15 +92,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 21, - "byte_offset": 2920, + "byte_length": 23, + "byte_offset": 1860, "text": "(return-from blk)" } ], "rule": "explicit-nil-return", "span": { - "end": 2941, - "start": 2920 + "end": 1883, + "start": 1860 } }, { @@ -110,14 +110,14 @@ "replacements": [ { "byte_length": 12, - "byte_offset": 1223, + "byte_offset": 916, "text": "(list e)" } ], "rule": "cons-to-list", "span": { - "end": 1235, - "start": 1223 + "end": 928, + "start": 916 } }, { @@ -127,14 +127,14 @@ "replacements": [ { "byte_length": 22, - "byte_offset": 1290, + "byte_offset": 945, "text": "(copy-seq dr)" } ], "rule": "double-reverse", "span": { - "end": 1312, - "start": 1290 + "end": 967, + "start": 945 } }, { @@ -144,14 +144,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 438, + "byte_offset": 437, "text": "5" } ], "rule": "redundant-quote", "span": { - "end": 440, - "start": 438 + "end": 439, + "start": 437 } }, { @@ -160,15 +160,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 12, - "byte_offset": 502, + "byte_length": 14, + "byte_offset": 460, "text": "only" } ], "rule": "redundant-progn", "span": { - "end": 514, - "start": 502 + "end": 474, + "start": 460 } }, { @@ -177,15 +177,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 11, - "byte_offset": 581, - "text": "b c" + "byte_length": 19, + "byte_offset": 507, + "text": "b\n c" } ], "rule": "nested-progn", "span": { - "end": 592, - "start": 581 + "end": 526, + "start": 507 } }, { @@ -194,15 +194,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 24, - "byte_offset": 3135, + "byte_length": 30, + "byte_offset": 2004, "text": "(when (and wa wb) (wc))" } ], "rule": "nested-when", "span": { - "end": 3159, - "start": 3135 + "end": 2034, + "start": 2004 } }, { @@ -211,15 +211,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 28, - "byte_offset": 3201, + "byte_length": 34, + "byte_offset": 2050, "text": "(unless (or ua ub) (uc))" } ], "rule": "nested-unless", "span": { - "end": 3229, - "start": 3201 + "end": 2084, + "start": 2050 } }, { @@ -229,14 +229,14 @@ "replacements": [ { "byte_length": 10, - "byte_offset": 3073, + "byte_offset": 1974, "text": "pb qc" } ], "rule": "nested-boolean", "span": { - "end": 3083, - "start": 3073 + "end": 1984, + "start": 1974 } }, { @@ -246,14 +246,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 3845, + "byte_offset": 2398, "text": "(cadr z)" } ], "rule": "nested-cxr", "span": { - "end": 3858, - "start": 3845 + "end": 2411, + "start": 2398 } }, { @@ -263,14 +263,14 @@ "replacements": [ { "byte_length": 10, - "byte_offset": 3910, + "byte_offset": 2426, "text": "(first zs)" } ], "rule": "nth-constant-index", "span": { - "end": 3920, - "start": 3910 + "end": 2436, + "start": 2426 } }, { @@ -280,14 +280,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 3983, + "byte_offset": 2459, "text": "nz" } ], "rule": "nthcdr-zero", "span": { - "end": 3996, - "start": 3983 + "end": 2472, + "start": 2459 } }, { @@ -297,14 +297,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 4049, + "byte_offset": 2488, "text": "(cddr ns)" } ], "rule": "nthcdr-small-index", "span": { - "end": 4062, - "start": 4049 + "end": 2501, + "start": 2488 } }, { @@ -313,15 +313,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 11, - "byte_offset": 665, - "text": "s t" + "byte_length": 19, + "byte_offset": 572, + "text": "s\n t" } ], "rule": "redundant-body-progn", "span": { - "end": 676, - "start": 665 + "end": 591, + "start": 572 } }, { @@ -331,14 +331,14 @@ "replacements": [ { "byte_length": 7, - "byte_offset": 732, + "byte_offset": 617, "text": "(progn" } ], "rule": "empty-let", "span": { - "end": 752, - "start": 732 + "end": 641, + "start": 617 } }, { @@ -347,15 +347,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 4, - "byte_offset": 803, + "byte_length": 8, + "byte_offset": 666, "text": "" } ], "rule": "redundant-if-nil", "span": { - "end": 808, - "start": 796 + "end": 675, + "start": 655 } }, { @@ -365,14 +365,14 @@ "replacements": [ { "byte_length": 4, - "byte_offset": 2560, + "byte_offset": 1656, "text": "let" } ], "rule": "redundant-let-star", "span": { - "end": 2575, - "start": 2559 + "end": 1673, + "start": 1655 } }, { @@ -382,14 +382,14 @@ "replacements": [ { "byte_length": 10, - "byte_offset": 868, + "byte_offset": 697, "text": "" } ], "rule": "redundant-funcall", "span": { - "end": 882, - "start": 867 + "end": 711, + "start": 696 } }, { @@ -399,14 +399,14 @@ "replacements": [ { "byte_length": 16, - "byte_offset": 939, + "byte_offset": 733, "text": "whatever" } ], "rule": "redundant-the", "span": { - "end": 955, - "start": 939 + "end": 749, + "start": 733 } }, { @@ -415,15 +415,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 8, - "byte_offset": 1008, + "byte_length": 9, + "byte_offset": 768, "text": "" } ], "rule": "funcall-lambda", "span": { - "end": 1035, - "start": 1007 + "end": 800, + "start": 767 } }, { @@ -432,15 +432,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 18, - "byte_offset": 1084, - "text": "(lambda (sq) sq)" + "byte_length": 23, + "byte_offset": 828, + "text": "(lambda (sq)\n sq)" } ], "rule": "sharp-quoted-lambda", "span": { - "end": 1102, - "start": 1084 + "end": 851, + "start": 828 } }, { @@ -450,14 +450,14 @@ "replacements": [ { "byte_length": 12, - "byte_offset": 1150, + "byte_offset": 881, "text": "h" } ], "rule": "redundant-identity", "span": { - "end": 1162, - "start": 1150 + "end": 893, + "start": 881 } }, { @@ -467,14 +467,14 @@ "replacements": [ { "byte_length": 20, - "byte_offset": 4122, + "byte_offset": 2524, "text": "(g m)" } ], "rule": "redundant-apply", "span": { - "end": 4142, - "start": 4122 + "end": 2544, + "start": 2524 } }, { @@ -484,14 +484,14 @@ "replacements": [ { "byte_length": 12, - "byte_offset": 4205, + "byte_offset": 2577, "text": "" } ], "rule": "redundant-eql-test", "span": { - "end": 4218, - "start": 4192 + "end": 2590, + "start": 2564 } }, { @@ -501,14 +501,14 @@ "replacements": [ { "byte_length": 16, - "byte_offset": 5465, + "byte_offset": 3472, "text": "" } ], "rule": "redundant-identity-key", "span": { - "end": 5482, - "start": 5452 + "end": 3489, + "start": 3459 } }, { @@ -518,19 +518,19 @@ "replacements": [ { "byte_length": 4, - "byte_offset": 3504, + "byte_offset": 2212, "text": "unless" }, { "byte_length": 7, - "byte_offset": 3509, + "byte_offset": 2217, "text": "r" } ], "rule": "negated-when-unless", "span": { - "end": 3519, - "start": 3503 + "end": 2229, + "start": 2211 } }, { @@ -540,14 +540,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 5599, + "byte_offset": 3547, "text": "(>= a b)" } ], "rule": "negated-comparison", "span": { - "end": 5612, - "start": 5599 + "end": 3560, + "start": 3547 } }, { @@ -556,15 +556,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 16, - "byte_offset": 5672, + "byte_length": 24, + "byte_offset": 3583, "text": "(if c b a)" } ], "rule": "negated-if", "span": { - "end": 5688, - "start": 5672 + "end": 3607, + "start": 3583 } }, { @@ -573,15 +573,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 13, - "byte_offset": 5737, + "byte_length": 21, + "byte_offset": 3622, "text": "(or iv jv)" } ], "rule": "if-to-or", "span": { - "end": 5750, - "start": 5737 + "end": 3643, + "start": 3622 } }, { @@ -590,15 +590,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 13, - "byte_offset": 5800, + "byte_length": 21, + "byte_offset": 3656, "text": "(not iw)" } ], "rule": "if-not", "span": { - "end": 5813, - "start": 5800 + "end": 3677, + "start": 3656 } }, { @@ -608,14 +608,14 @@ "replacements": [ { "byte_length": 9, - "byte_offset": 6155, + "byte_offset": 3872, "text": "(1+ osa)" } ], "rule": "one-step-arithmetic", "span": { - "end": 6164, - "start": 6155 + "end": 3881, + "start": 3872 } }, { @@ -625,14 +625,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 3578, + "byte_offset": 2254, "text": "when" } ], "rule": "one-armed-if", "span": { - "end": 3585, - "start": 3577 + "end": 2265, + "start": 2253 } }, { @@ -642,14 +642,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 6518, + "byte_offset": 4062, "text": "(null w)" } ], "rule": "nil-comparison", "span": { - "end": 6531, - "start": 6518 + "end": 4075, + "start": 4062 } }, { @@ -658,15 +658,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 13, - "byte_offset": 6229, + "byte_length": 21, + "byte_offset": 3905, "text": "on" } ], "rule": "constant-if-test", "span": { - "end": 6242, - "start": 6229 + "end": 3926, + "start": 3905 } }, { @@ -676,14 +676,14 @@ "replacements": [ { "byte_length": 7, - "byte_offset": 6300, + "byte_offset": 3947, "text": "(progn" } ], "rule": "constant-when-test", "span": { - "end": 6313, - "start": 6300 + "end": 3962, + "start": 3947 } }, { @@ -693,14 +693,14 @@ "replacements": [ { "byte_length": 21, - "byte_offset": 1359, + "byte_offset": 986, "text": "(cons al ar)" } ], "rule": "append-list-to-cons", "span": { - "end": 1380, - "start": 1359 + "end": 1007, + "start": 986 } }, { @@ -710,14 +710,14 @@ "replacements": [ { "byte_length": 20, - "byte_offset": 1433, + "byte_offset": 1031, "text": "(princ-to-string fs)" } ], "rule": "format-to-string", "span": { - "end": 1453, - "start": 1433 + "end": 1051, + "start": 1031 } }, { @@ -727,14 +727,14 @@ "replacements": [ { "byte_length": 15, - "byte_offset": 1504, + "byte_offset": 1072, "text": "(terpri)" } ], "rule": "format-newline", "span": { - "end": 1519, - "start": 1504 + "end": 1087, + "start": 1072 } }, { @@ -744,14 +744,14 @@ "replacements": [ { "byte_length": 12, - "byte_offset": 1573, + "byte_offset": 1106, "text": "(floor fq)" } ], "rule": "redundant-divisor", "span": { - "end": 1585, - "start": 1573 + "end": 1118, + "start": 1106 } }, { @@ -761,14 +761,14 @@ "replacements": [ { "byte_length": 11, - "byte_offset": 6373, + "byte_offset": 3985, "text": "(and p q)" } ], "rule": "redundant-boolean-identity", "span": { - "end": 6384, - "start": 6373 + "end": 3996, + "start": 3985 } }, { @@ -778,14 +778,14 @@ "replacements": [ { "byte_length": 21, - "byte_offset": 6454, + "byte_offset": 4027, "text": "(not (or p q))" } ], "rule": "de-morgan", "span": { - "end": 6475, - "start": 6454 + "end": 4048, + "start": 4027 } }, { @@ -795,14 +795,14 @@ "replacements": [ { "byte_length": 7, - "byte_offset": 3269, + "byte_offset": 2102, "text": "x" } ], "rule": "single-operand-boolean", "span": { - "end": 3276, - "start": 3269 + "end": 2109, + "start": 2102 } }, { @@ -812,14 +812,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 3346, + "byte_offset": 2136, "text": "solo" } ], "rule": "single-operand-list-op", "span": { - "end": 3359, - "start": 3346 + "end": 2149, + "start": 2136 } }, { @@ -829,14 +829,14 @@ "replacements": [ { "byte_length": 5, - "byte_offset": 3423, + "byte_offset": 2176, "text": "x" } ], "rule": "single-operand-arithmetic", "span": { - "end": 3428, - "start": 3423 + "end": 2181, + "start": 2176 } }, { @@ -846,14 +846,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 6588, + "byte_offset": 4095, "text": "eql" } ], "rule": "eq-number-comparison", "span": { - "end": 6595, - "start": 6587 + "end": 4102, + "start": 4094 } }, { @@ -863,14 +863,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 6663, + "byte_offset": 4128, "text": "eql" } ], "rule": "eq-char-comparison", "span": { - "end": 6672, - "start": 6662 + "end": 4137, + "start": 4127 } }, { @@ -880,14 +880,14 @@ "replacements": [ { "byte_length": 11, - "byte_offset": 5529, + "byte_offset": 3516, "text": "(zerop tally)" } ], "rule": "sign-comparison", "span": { - "end": 5540, - "start": 5529 + "end": 3527, + "start": 3516 } }, { @@ -896,15 +896,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 17, - "byte_offset": 2632, + "byte_length": 19, + "byte_offset": 1696, "text": "(when ok (run))" } ], "rule": "single-clause-cond", "span": { - "end": 2649, - "start": 2632 + "end": 1715, + "start": 1696 } }, { @@ -913,15 +913,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 20, - "byte_offset": 2705, - "text": "(progn (r1) (r2))" + "byte_length": 30, + "byte_offset": 1738, + "text": "(progn (r1)\n (r2))" } ], "rule": "cond-t-clause", "span": { - "end": 2725, - "start": 2705 + "end": 1768, + "start": 1738 } }, { @@ -930,15 +930,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 36, - "byte_offset": 2994, + "byte_length": 38, + "byte_offset": 1907, "text": "(let ((mv (vals))) mv)" } ], "rule": "single-value-bind", "span": { - "end": 3030, - "start": 2994 + "end": 1945, + "start": 1907 } }, { @@ -948,14 +948,14 @@ "replacements": [ { "byte_length": 9, - "byte_offset": 1645, + "byte_offset": 1140, "text": "(- amt)" } ], "rule": "verbose-negation", "span": { - "end": 1654, - "start": 1645 + "end": 1149, + "start": 1140 } }, { @@ -965,14 +965,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 1716, + "byte_offset": 1170, "text": "(cons la lb)" } ], "rule": "list-star-to-cons", "span": { - "end": 1729, - "start": 1716 + "end": 1183, + "start": 1170 } }, { @@ -982,14 +982,14 @@ "replacements": [ { "byte_length": 26, - "byte_offset": 1788, + "byte_offset": 1205, "text": "(values va vb)" } ], "rule": "values-list-of-list", "span": { - "end": 1814, - "start": 1788 + "end": 1231, + "start": 1205 } }, { @@ -998,15 +998,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 13, - "byte_offset": 1862, + "byte_length": 15, + "byte_offset": 1255, "text": "(p1x)" } ], "rule": "redundant-prog1", "span": { - "end": 1875, - "start": 1862 + "end": 1270, + "start": 1255 } }, { @@ -1016,14 +1016,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 1932, + "byte_offset": 1290, "text": "(copy-seq sz)" } ], "rule": "subseq-zero", "span": { - "end": 1945, - "start": 1932 + "end": 1303, + "start": 1290 } }, { @@ -1033,14 +1033,14 @@ "replacements": [ { "byte_length": 20, - "byte_offset": 1998, + "byte_offset": 1319, "text": "(nth cn cx)" } ], "rule": "car-nthcdr", "span": { - "end": 2018, - "start": 1998 + "end": 1339, + "start": 1319 } }, { @@ -1050,14 +1050,14 @@ "replacements": [ { "byte_length": 19, - "byte_offset": 2063, + "byte_offset": 1354, "text": "(car (last crx))" } ], "rule": "car-reverse", "span": { - "end": 2082, - "start": 2063 + "end": 1373, + "start": 1354 } }, { @@ -1067,14 +1067,14 @@ "replacements": [ { "byte_length": 16, - "byte_offset": 2129, + "byte_offset": 1389, "text": "(copy-list anx)" } ], "rule": "append-nil", "span": { - "end": 2145, - "start": 2129 + "end": 1405, + "start": 1389 } }, { @@ -1084,14 +1084,14 @@ "replacements": [ { "byte_length": 38, - "byte_offset": 2194, + "byte_offset": 1420, "text": "(list mva mvb)" } ], "rule": "multiple-value-list-of-values", "span": { - "end": 2232, - "start": 2194 + "end": 1458, + "start": 1420 } }, { @@ -1101,14 +1101,14 @@ "replacements": [ { "byte_length": 19, - "byte_offset": 2278, + "byte_offset": 1492, "text": "(stringp tpx)" } ], "rule": "typep-predicate", "span": { - "end": 2297, - "start": 2278 + "end": 1511, + "start": 1492 } }, { @@ -1118,14 +1118,14 @@ "replacements": [ { "byte_length": 14, - "byte_offset": 2348, + "byte_offset": 1531, "text": "ctx" } ], "rule": "coerce-to-t", "span": { - "end": 2362, - "start": 2348 + "end": 1545, + "start": 1531 } }, { @@ -1135,14 +1135,14 @@ "replacements": [ { "byte_length": 4, - "byte_offset": 2430, + "byte_offset": 1577, "text": "" } ], "rule": "gethash-default", "span": { - "end": 2435, - "start": 2414 + "end": 1582, + "start": 1561 } }, { @@ -1152,14 +1152,14 @@ "replacements": [ { "byte_length": 11, - "byte_offset": 2500, + "byte_offset": 1618, "text": "" } ], "rule": "make-hash-table-test", "span": { - "end": 2512, - "start": 2484 + "end": 1630, + "start": 1602 } }, { @@ -1168,15 +1168,15 @@ "path": "broad.lisp", "replacements": [ { - "byte_length": 17, - "byte_offset": 5861, + "byte_length": 25, + "byte_offset": 3688, "text": "(unless iu (iue))" } ], "rule": "if-to-unless", "span": { - "end": 5878, - "start": 5861 + "end": 3713, + "start": 3688 } }, { @@ -1186,14 +1186,14 @@ "replacements": [ { "byte_length": 5, - "byte_offset": 5929, + "byte_offset": 3731, "text": "progn" } ], "rule": "prog2-to-progn", "span": { - "end": 5947, - "start": 5928 + "end": 3753, + "start": 3730 } }, { @@ -1203,14 +1203,14 @@ "replacements": [ { "byte_length": 20, - "byte_offset": 5997, + "byte_offset": 3772, "text": "(hcx)" } ], "rule": "handler-case-no-clauses", "span": { - "end": 6017, - "start": 5997 + "end": 3792, + "start": 3772 } }, { @@ -1220,14 +1220,14 @@ "replacements": [ { "byte_length": 22, - "byte_offset": 6075, + "byte_offset": 3820, "text": "(upx)" } ], "rule": "unwind-protect-no-cleanup", "span": { - "end": 6097, - "start": 6075 + "end": 3842, + "start": 3820 } }, { @@ -1237,14 +1237,14 @@ "replacements": [ { "byte_length": 9, - "byte_offset": 4278, + "byte_offset": 2626, "text": "" } ], "rule": "redundant-start-zero", "span": { - "end": 4288, - "start": 4265 + "end": 2636, + "start": 2613 } }, { @@ -1254,14 +1254,14 @@ "replacements": [ { "byte_length": 9, - "byte_offset": 4353, + "byte_offset": 2674, "text": "" } ], "rule": "redundant-end-nil", "span": { - "end": 4363, - "start": 4340 + "end": 2684, + "start": 2661 } }, { @@ -1271,14 +1271,14 @@ "replacements": [ { "byte_length": 14, - "byte_offset": 4425, + "byte_offset": 2719, "text": "" } ], "rule": "redundant-from-end-nil", "span": { - "end": 4440, - "start": 4412 + "end": 2734, + "start": 2706 } }, { @@ -1288,14 +1288,14 @@ "replacements": [ { "byte_length": 11, - "byte_offset": 4504, + "byte_offset": 2776, "text": "" } ], "rule": "redundant-count-nil", "span": { - "end": 4516, - "start": 4489 + "end": 2788, + "start": 2761 } }, { @@ -1305,14 +1305,14 @@ "replacements": [ { "byte_length": 51, - "byte_offset": 4563, + "byte_offset": 2812, "text": "(string-equal sa sb)" } ], "rule": "string-case-fold", "span": { - "end": 4614, - "start": 4563 + "end": 2863, + "start": 2812 } }, { @@ -1322,14 +1322,14 @@ "replacements": [ { "byte_length": 45, - "byte_offset": 4634, + "byte_offset": 2884, "text": "(char-equal ca cb)" } ], "rule": "char-case-fold", "span": { - "end": 4679, - "start": 4634 + "end": 2929, + "start": 2884 } }, { @@ -1339,14 +1339,14 @@ "replacements": [ { "byte_length": 37, - "byte_offset": 4703, + "byte_offset": 2948, "text": "(string-upcase nsc)" } ], "rule": "nested-string-case", "span": { - "end": 4740, - "start": 4703 + "end": 2985, + "start": 2948 } }, { @@ -1356,14 +1356,14 @@ "replacements": [ { "byte_length": 27, - "byte_offset": 4776, + "byte_offset": 3008, "text": "ccc" } ], "rule": "code-char-char-code", "span": { - "end": 4803, - "start": 4776 + "end": 3035, + "start": 3008 } }, { @@ -1373,14 +1373,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 4859, + "byte_offset": 3068, "text": "" } ], "rule": "last-default-count", "span": { - "end": 4862, - "start": 4850 + "end": 3071, + "start": 3059 } }, { @@ -1390,14 +1390,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 4935, + "byte_offset": 3106, "text": "" } ], "rule": "butlast-default-count", "span": { - "end": 4938, - "start": 4923 + "end": 3109, + "start": 3094 } }, { @@ -1407,14 +1407,14 @@ "replacements": [ { "byte_length": 21, - "byte_offset": 5013, + "byte_offset": 3149, "text": "" } ], "rule": "make-list-default-element", "span": { - "end": 5035, - "start": 4999 + "end": 3171, + "start": 3135 } }, { @@ -1424,14 +1424,14 @@ "replacements": [ { "byte_length": 10, - "byte_offset": 5097, + "byte_offset": 3219, "text": "" } ], "rule": "parse-integer-default-radix", "span": { - "end": 5108, - "start": 5079 + "end": 3230, + "start": 3201 } }, { @@ -1441,14 +1441,14 @@ "replacements": [ { "byte_length": 4, - "byte_offset": 5175, + "byte_offset": 3276, "text": "" } ], "rule": "getf-default-nil", "span": { - "end": 5180, - "start": 5161 + "end": 3281, + "start": 3262 } }, { @@ -1458,14 +1458,14 @@ "replacements": [ { "byte_length": 16, - "byte_offset": 5248, + "byte_offset": 3318, "text": "" } ], "rule": "make-array-default-keyword", "span": { - "end": 5265, - "start": 5232 + "end": 3335, + "start": 3302 } }, { @@ -1475,14 +1475,14 @@ "replacements": [ { "byte_length": 33, - "byte_offset": 5313, + "byte_offset": 3366, "text": "(char-upcase ncc)" } ], "rule": "nested-char-case", "span": { - "end": 5346, - "start": 5313 + "end": 3399, + "start": 3366 } }, { @@ -1492,19 +1492,19 @@ "replacements": [ { "byte_length": 5, - "byte_offset": 5385, + "byte_offset": 3421, "text": "list" }, { "byte_length": 4, - "byte_offset": 5400, + "byte_offset": 3436, "text": "" } ], "rule": "list-star-nil", "span": { - "end": 5405, - "start": 5384 + "end": 3441, + "start": 3420 } } ], diff --git a/tests/fixtures/lint_golden/expected/broad.json.golden b/tests/fixtures/lint_golden/expected/broad.json.golden index 37ea85b29..231e0ed30 100644 --- a/tests/fixtures/lint_golden/expected/broad.json.golden +++ b/tests/fixtures/lint_golden/expected/broad.json.golden @@ -10,8 +10,8 @@ "rule": "self-assignment", "severity": "error", "span": { - "end": 6885, - "start": 6875 + "end": 4283, + "start": 4273 } }, { @@ -23,8 +23,8 @@ "rule": "duplicate-setf-places", "severity": "error", "span": { - "end": 6983, - "start": 6961 + "end": 4351, + "start": 4321 } }, { @@ -36,8 +36,8 @@ "rule": "setf-arity", "severity": "error", "span": { - "end": 7047, - "start": 7021 + "end": 4410, + "start": 4378 } }, { @@ -49,8 +49,8 @@ "rule": "setq-non-variable", "severity": "error", "span": { - "end": 7099, - "start": 7092 + "end": 4438, + "start": 4431 } }, { @@ -62,8 +62,8 @@ "rule": "manual-incf", "severity": "warning", "span": { - "end": 3663, - "start": 3644 + "end": 2301, + "start": 2282 } }, { @@ -75,8 +75,8 @@ "rule": "manual-push", "severity": "warning", "span": { - "end": 3733, - "start": 3710 + "end": 2340, + "start": 2317 } }, { @@ -88,8 +88,8 @@ "rule": "manual-pushnew", "severity": "warning", "span": { - "end": 3799, - "start": 3776 + "end": 2379, + "start": 2356 } }, { @@ -101,8 +101,8 @@ "rule": "explicit-step-delta", "severity": "warning", "span": { - "end": 2787, - "start": 2773 + "end": 1800, + "start": 1786 } }, { @@ -114,8 +114,8 @@ "rule": "negated-step-delta", "severity": "warning", "span": { - "end": 2860, - "start": 2847 + "end": 1837, + "start": 1824 } }, { @@ -127,8 +127,8 @@ "rule": "explicit-nil-return", "severity": "warning", "span": { - "end": 2941, - "start": 2920 + "end": 1883, + "start": 1860 } }, { @@ -140,8 +140,8 @@ "rule": "cons-to-list", "severity": "warning", "span": { - "end": 1235, - "start": 1223 + "end": 928, + "start": 916 } }, { @@ -153,8 +153,8 @@ "rule": "double-reverse", "severity": "warning", "span": { - "end": 1312, - "start": 1290 + "end": 967, + "start": 945 } }, { @@ -166,8 +166,8 @@ "rule": "modify-macro-arity", "severity": "error", "span": { - "end": 7176, - "start": 7158 + "end": 4481, + "start": 4463 } }, { @@ -179,8 +179,8 @@ "rule": "duplicate-parameters", "severity": "error", "span": { - "end": 7275, - "start": 7231 + "end": 4550, + "start": 4504 } }, { @@ -192,8 +192,8 @@ "rule": "duplicate-lambda-list-keyword", "severity": "error", "span": { - "end": 7347, - "start": 7306 + "end": 4618, + "start": 4575 } }, { @@ -205,8 +205,8 @@ "rule": "lambda-list-keyword-order", "severity": "error", "span": { - "end": 7428, - "start": 7390 + "end": 4692, + "start": 4652 } }, { @@ -218,8 +218,8 @@ "rule": "redundant-quote", "severity": "warning", "span": { - "end": 440, - "start": 438 + "end": 439, + "start": 437 } }, { @@ -231,8 +231,8 @@ "rule": "redundant-progn", "severity": "warning", "span": { - "end": 514, - "start": 502 + "end": 474, + "start": 460 } }, { @@ -244,8 +244,8 @@ "rule": "nested-progn", "severity": "warning", "span": { - "end": 592, - "start": 581 + "end": 526, + "start": 507 } }, { @@ -257,8 +257,8 @@ "rule": "nested-when", "severity": "warning", "span": { - "end": 3159, - "start": 3135 + "end": 2034, + "start": 2004 } }, { @@ -270,8 +270,8 @@ "rule": "nested-unless", "severity": "warning", "span": { - "end": 3229, - "start": 3201 + "end": 2084, + "start": 2050 } }, { @@ -283,8 +283,8 @@ "rule": "nested-boolean", "severity": "warning", "span": { - "end": 3083, - "start": 3073 + "end": 1984, + "start": 1974 } }, { @@ -296,8 +296,8 @@ "rule": "nested-cxr", "severity": "warning", "span": { - "end": 3858, - "start": 3845 + "end": 2411, + "start": 2398 } }, { @@ -309,8 +309,8 @@ "rule": "nth-constant-index", "severity": "warning", "span": { - "end": 3920, - "start": 3910 + "end": 2436, + "start": 2426 } }, { @@ -322,8 +322,8 @@ "rule": "nthcdr-zero", "severity": "warning", "span": { - "end": 3996, - "start": 3983 + "end": 2472, + "start": 2459 } }, { @@ -335,8 +335,8 @@ "rule": "nthcdr-small-index", "severity": "warning", "span": { - "end": 4062, - "start": 4049 + "end": 2501, + "start": 2488 } }, { @@ -348,8 +348,8 @@ "rule": "redundant-body-progn", "severity": "warning", "span": { - "end": 676, - "start": 665 + "end": 591, + "start": 572 } }, { @@ -361,8 +361,8 @@ "rule": "empty-let", "severity": "warning", "span": { - "end": 752, - "start": 732 + "end": 641, + "start": 617 } }, { @@ -374,8 +374,8 @@ "rule": "redundant-if-nil", "severity": "warning", "span": { - "end": 808, - "start": 796 + "end": 675, + "start": 655 } }, { @@ -387,8 +387,8 @@ "rule": "redundant-let-star", "severity": "warning", "span": { - "end": 2575, - "start": 2559 + "end": 1673, + "start": 1655 } }, { @@ -400,8 +400,8 @@ "rule": "redundant-funcall", "severity": "warning", "span": { - "end": 882, - "start": 867 + "end": 711, + "start": 696 } }, { @@ -413,8 +413,8 @@ "rule": "redundant-the", "severity": "warning", "span": { - "end": 955, - "start": 939 + "end": 749, + "start": 733 } }, { @@ -426,8 +426,8 @@ "rule": "funcall-lambda", "severity": "warning", "span": { - "end": 1035, - "start": 1007 + "end": 800, + "start": 767 } }, { @@ -439,8 +439,8 @@ "rule": "sharp-quoted-lambda", "severity": "warning", "span": { - "end": 1102, - "start": 1084 + "end": 851, + "start": 828 } }, { @@ -452,8 +452,8 @@ "rule": "redundant-identity", "severity": "warning", "span": { - "end": 1162, - "start": 1150 + "end": 893, + "start": 881 } }, { @@ -465,8 +465,8 @@ "rule": "redundant-apply", "severity": "warning", "span": { - "end": 4142, - "start": 4122 + "end": 2544, + "start": 2524 } }, { @@ -478,8 +478,8 @@ "rule": "redundant-eql-test", "severity": "warning", "span": { - "end": 4218, - "start": 4192 + "end": 2590, + "start": 2564 } }, { @@ -491,8 +491,8 @@ "rule": "redundant-identity-key", "severity": "warning", "span": { - "end": 5482, - "start": 5452 + "end": 3489, + "start": 3459 } }, { @@ -504,8 +504,8 @@ "rule": "negated-when-unless", "severity": "warning", "span": { - "end": 3519, - "start": 3503 + "end": 2229, + "start": 2211 } }, { @@ -517,8 +517,8 @@ "rule": "negated-comparison", "severity": "warning", "span": { - "end": 5612, - "start": 5599 + "end": 3560, + "start": 3547 } }, { @@ -530,8 +530,8 @@ "rule": "negated-if", "severity": "warning", "span": { - "end": 5688, - "start": 5672 + "end": 3607, + "start": 3583 } }, { @@ -543,8 +543,8 @@ "rule": "if-to-or", "severity": "warning", "span": { - "end": 5750, - "start": 5737 + "end": 3643, + "start": 3622 } }, { @@ -556,8 +556,8 @@ "rule": "if-not", "severity": "warning", "span": { - "end": 5813, - "start": 5800 + "end": 3677, + "start": 3656 } }, { @@ -569,8 +569,8 @@ "rule": "one-step-arithmetic", "severity": "warning", "span": { - "end": 6164, - "start": 6155 + "end": 3881, + "start": 3872 } }, { @@ -582,8 +582,8 @@ "rule": "one-armed-if", "severity": "warning", "span": { - "end": 3585, - "start": 3577 + "end": 2265, + "start": 2253 } }, { @@ -595,8 +595,8 @@ "rule": "self-comparison", "severity": "error", "span": { - "end": 7494, - "start": 7476 + "end": 4746, + "start": 4728 } }, { @@ -608,8 +608,8 @@ "rule": "nil-comparison", "severity": "warning", "span": { - "end": 6531, - "start": 6518 + "end": 4075, + "start": 4062 } }, { @@ -621,8 +621,8 @@ "rule": "t-comparison", "severity": "warning", "span": { - "end": 7576, - "start": 7558 + "end": 4809, + "start": 4791 } }, { @@ -634,8 +634,8 @@ "rule": "identical-if-branches", "severity": "error", "span": { - "end": 7632, - "start": 7607 + "end": 4860, + "start": 4827 } }, { @@ -647,8 +647,8 @@ "rule": "constant-if-test", "severity": "warning", "span": { - "end": 6242, - "start": 6229 + "end": 3926, + "start": 3905 } }, { @@ -660,8 +660,8 @@ "rule": "constant-when-test", "severity": "warning", "span": { - "end": 6313, - "start": 6300 + "end": 3962, + "start": 3947 } }, { @@ -673,8 +673,8 @@ "rule": "if-arity", "severity": "error", "span": { - "end": 6747, - "start": 6735 + "end": 4184, + "start": 4160 } }, { @@ -686,8 +686,8 @@ "rule": "the-arity", "severity": "error", "span": { - "end": 7695, - "start": 7683 + "end": 4898, + "start": 4886 } }, { @@ -699,8 +699,8 @@ "rule": "equality-arity", "severity": "warning", "span": { - "end": 7753, - "start": 7747 + "end": 4918, + "start": 4912 } }, { @@ -712,8 +712,8 @@ "rule": "accessor-arity", "severity": "error", "span": { - "end": 7829, - "start": 7816 + "end": 4950, + "start": 4937 } }, { @@ -725,8 +725,8 @@ "rule": "append-list-to-cons", "severity": "warning", "span": { - "end": 1380, - "start": 1359 + "end": 1007, + "start": 986 } }, { @@ -738,8 +738,8 @@ "rule": "format-to-string", "severity": "warning", "span": { - "end": 1453, - "start": 1433 + "end": 1051, + "start": 1031 } }, { @@ -751,8 +751,8 @@ "rule": "format-newline", "severity": "warning", "span": { - "end": 1519, - "start": 1504 + "end": 1087, + "start": 1072 } }, { @@ -764,8 +764,8 @@ "rule": "redundant-divisor", "severity": "warning", "span": { - "end": 1585, - "start": 1573 + "end": 1118, + "start": 1106 } }, { @@ -777,8 +777,8 @@ "rule": "duplicate-case-keys", "severity": "error", "span": { - "end": 7914, - "start": 7885 + "end": 5004, + "start": 4969 } }, { @@ -790,8 +790,8 @@ "rule": "quoted-case-key", "severity": "error", "span": { - "end": 7976, - "start": 7970 + "end": 5047, + "start": 5041 } }, { @@ -803,8 +803,8 @@ "rule": "quoted-case-key", "severity": "error", "span": { - "end": 7993, - "start": 7986 + "end": 5066, + "start": 5059 } }, { @@ -816,8 +816,8 @@ "rule": "case-nil-key", "severity": "error", "span": { - "end": 8041, - "start": 8038 + "end": 5116, + "start": 5113 } }, { @@ -829,8 +829,8 @@ "rule": "typecase-nil-key", "severity": "error", "span": { - "end": 8112, - "start": 8109 + "end": 5163, + "start": 5160 } }, { @@ -842,8 +842,8 @@ "rule": "malformed-case-clause", "severity": "error", "span": { - "end": 8185, - "start": 8184 + "end": 5218, + "start": 5217 } }, { @@ -855,8 +855,8 @@ "rule": "malformed-case-clause", "severity": "error", "span": { - "end": 8190, - "start": 8186 + "end": 5225, + "start": 5221 } }, { @@ -868,8 +868,8 @@ "rule": "unreachable-case-clause", "severity": "error", "span": { - "end": 8277, - "start": 8269 + "end": 5292, + "start": 5284 } }, { @@ -881,8 +881,8 @@ "rule": "exhaustive-case-otherwise", "severity": "error", "span": { - "end": 8351, - "start": 8339 + "end": 5355, + "start": 5343 } }, { @@ -894,8 +894,8 @@ "rule": "duplicate-cond-tests", "severity": "error", "span": { - "end": 8437, - "start": 8401 + "end": 5428, + "start": 5386 } }, { @@ -907,8 +907,8 @@ "rule": "unreachable-cond-clause", "severity": "error", "span": { - "end": 8507, - "start": 8498 + "end": 5490, + "start": 5481 } }, { @@ -920,8 +920,8 @@ "rule": "malformed-cond-clause", "severity": "error", "span": { - "end": 8600, - "start": 8595 + "end": 5571, + "start": 5566 } }, { @@ -933,8 +933,8 @@ "rule": "duplicate-let-bindings", "severity": "error", "span": { - "end": 8657, - "start": 8630 + "end": 5639, + "start": 5598 } }, { @@ -946,8 +946,8 @@ "rule": "malformed-let-binding", "severity": "error", "span": { - "end": 8722, - "start": 8713 + "end": 5681, + "start": 5672 } }, { @@ -959,8 +959,8 @@ "rule": "binds-constant", "severity": "error", "span": { - "end": 8796, - "start": 8789 + "end": 5732, + "start": 5725 } }, { @@ -972,8 +972,8 @@ "rule": "binds-constant", "severity": "error", "span": { - "end": 8810, - "start": 8797 + "end": 5752, + "start": 5739 } }, { @@ -985,8 +985,8 @@ "rule": "malformed-iteration-spec", "severity": "error", "span": { - "end": 8863, - "start": 8860 + "end": 5794, + "start": 5791 } }, { @@ -998,8 +998,8 @@ "rule": "eval-when-situation", "severity": "error", "span": { - "end": 8970, - "start": 8961 + "end": 5875, + "start": 5866 } }, { @@ -1011,8 +1011,8 @@ "rule": "duplicate-boolean-operands", "severity": "error", "span": { - "end": 9015, - "start": 9005 + "end": 5915, + "start": 5905 } }, { @@ -1024,8 +1024,8 @@ "rule": "dead-boolean-operand", "severity": "error", "span": { - "end": 9118, - "start": 9086 + "end": 5978, + "start": 5946 } }, { @@ -1037,8 +1037,8 @@ "rule": "redundant-boolean-identity", "severity": "warning", "span": { - "end": 6384, - "start": 6373 + "end": 3996, + "start": 3985 } }, { @@ -1050,8 +1050,8 @@ "rule": "de-morgan", "severity": "warning", "span": { - "end": 6475, - "start": 6454 + "end": 4048, + "start": 4027 } }, { @@ -1063,8 +1063,8 @@ "rule": "single-operand-boolean", "severity": "warning", "span": { - "end": 3276, - "start": 3269 + "end": 2109, + "start": 2102 } }, { @@ -1076,8 +1076,8 @@ "rule": "single-operand-list-op", "severity": "warning", "span": { - "end": 3359, - "start": 3346 + "end": 2149, + "start": 2136 } }, { @@ -1089,8 +1089,8 @@ "rule": "single-operand-arithmetic", "severity": "warning", "span": { - "end": 3428, - "start": 3423 + "end": 2181, + "start": 2176 } }, { @@ -1102,8 +1102,8 @@ "rule": "eql-string-comparison", "severity": "error", "span": { - "end": 9184, - "start": 9167 + "end": 6026, + "start": 6009 } }, { @@ -1115,8 +1115,8 @@ "rule": "eql-list-comparison", "severity": "error", "span": { - "end": 9259, - "start": 9243 + "end": 6079, + "start": 6063 } }, { @@ -1128,8 +1128,8 @@ "rule": "eql-search-literal", "severity": "error", "span": { - "end": 9354, - "start": 9336 + "end": 6153, + "start": 6135 } }, { @@ -1141,8 +1141,8 @@ "rule": "eq-number-comparison", "severity": "error", "span": { - "end": 6595, - "start": 6587 + "end": 4102, + "start": 4094 } }, { @@ -1154,8 +1154,8 @@ "rule": "eq-char-comparison", "severity": "error", "span": { - "end": 6672, - "start": 6662 + "end": 4137, + "start": 4127 } }, { @@ -1167,8 +1167,8 @@ "rule": "single-arg-comparison", "severity": "error", "span": { - "end": 9416, - "start": 9411 + "end": 6211, + "start": 6206 } }, { @@ -1180,8 +1180,8 @@ "rule": "sign-comparison", "severity": "warning", "span": { - "end": 5540, - "start": 5529 + "end": 3527, + "start": 3516 } }, { @@ -1193,8 +1193,8 @@ "rule": "single-clause-cond", "severity": "warning", "span": { - "end": 2649, - "start": 2632 + "end": 1715, + "start": 1696 } }, { @@ -1206,8 +1206,8 @@ "rule": "cond-t-clause", "severity": "warning", "span": { - "end": 2725, - "start": 2705 + "end": 1768, + "start": 1738 } }, { @@ -1219,8 +1219,8 @@ "rule": "single-value-bind", "severity": "warning", "span": { - "end": 3030, - "start": 2994 + "end": 1945, + "start": 1907 } }, { @@ -1232,8 +1232,8 @@ "rule": "format-missing-destination", "severity": "error", "span": { - "end": 9500, - "start": 9483 + "end": 6290, + "start": 6273 } }, { @@ -1245,8 +1245,8 @@ "rule": "literal-place", "severity": "error", "span": { - "end": 9568, - "start": 9560 + "end": 6351, + "start": 6343 } }, { @@ -1258,8 +1258,8 @@ "rule": "destructive-literal", "severity": "error", "span": { - "end": 9647, - "start": 9628 + "end": 6410, + "start": 6391 } }, { @@ -1271,8 +1271,8 @@ "rule": "char-op-string", "severity": "error", "span": { - "end": 9724, - "start": 9711 + "end": 6477, + "start": 6464 } }, { @@ -1284,8 +1284,8 @@ "rule": "empty-body", "severity": "warning", "span": { - "end": 9790, - "start": 9778 + "end": 6546, + "start": 6534 } }, { @@ -1297,8 +1297,8 @@ "rule": "identity-arithmetic", "severity": "warning", "span": { - "end": 9847, - "start": 9840 + "end": 6593, + "start": 6586 } }, { @@ -1310,8 +1310,8 @@ "rule": "verbose-negation", "severity": "warning", "span": { - "end": 1654, - "start": 1645 + "end": 1149, + "start": 1140 } }, { @@ -1323,8 +1323,8 @@ "rule": "list-star-to-cons", "severity": "warning", "span": { - "end": 1729, - "start": 1716 + "end": 1183, + "start": 1170 } }, { @@ -1336,8 +1336,8 @@ "rule": "values-list-of-list", "severity": "warning", "span": { - "end": 1814, - "start": 1788 + "end": 1231, + "start": 1205 } }, { @@ -1349,8 +1349,8 @@ "rule": "redundant-prog1", "severity": "warning", "span": { - "end": 1875, - "start": 1862 + "end": 1270, + "start": 1255 } }, { @@ -1362,8 +1362,8 @@ "rule": "subseq-zero", "severity": "warning", "span": { - "end": 1945, - "start": 1932 + "end": 1303, + "start": 1290 } }, { @@ -1375,8 +1375,8 @@ "rule": "car-nthcdr", "severity": "warning", "span": { - "end": 2018, - "start": 1998 + "end": 1339, + "start": 1319 } }, { @@ -1388,8 +1388,8 @@ "rule": "car-reverse", "severity": "warning", "span": { - "end": 2082, - "start": 2063 + "end": 1373, + "start": 1354 } }, { @@ -1401,8 +1401,8 @@ "rule": "append-nil", "severity": "warning", "span": { - "end": 2145, - "start": 2129 + "end": 1405, + "start": 1389 } }, { @@ -1414,8 +1414,8 @@ "rule": "multiple-value-list-of-values", "severity": "warning", "span": { - "end": 2232, - "start": 2194 + "end": 1458, + "start": 1420 } }, { @@ -1427,8 +1427,8 @@ "rule": "typep-predicate", "severity": "warning", "span": { - "end": 2297, - "start": 2278 + "end": 1511, + "start": 1492 } }, { @@ -1440,8 +1440,8 @@ "rule": "coerce-to-t", "severity": "warning", "span": { - "end": 2362, - "start": 2348 + "end": 1545, + "start": 1531 } }, { @@ -1453,8 +1453,8 @@ "rule": "gethash-default", "severity": "warning", "span": { - "end": 2435, - "start": 2414 + "end": 1582, + "start": 1561 } }, { @@ -1466,8 +1466,8 @@ "rule": "make-hash-table-test", "severity": "warning", "span": { - "end": 2512, - "start": 2484 + "end": 1630, + "start": 1602 } }, { @@ -1479,8 +1479,8 @@ "rule": "zero-divisor", "severity": "warning", "span": { - "end": 9899, - "start": 9892 + "end": 6625, + "start": 6618 } }, { @@ -1492,8 +1492,8 @@ "rule": "duplicate-keyword", "severity": "warning", "span": { - "end": 9987, - "start": 9959 + "end": 6670, + "start": 6642 } }, { @@ -1505,8 +1505,8 @@ "rule": "defpackage-quoted", "severity": "warning", "span": { - "end": 10063, - "start": 10031 + "end": 6724, + "start": 6692 } }, { @@ -1518,8 +1518,8 @@ "rule": "step-zero", "severity": "warning", "span": { - "end": 10119, - "start": 10103 + "end": 6762, + "start": 6746 } }, { @@ -1531,8 +1531,8 @@ "rule": "if-to-unless", "severity": "warning", "span": { - "end": 5878, - "start": 5861 + "end": 3713, + "start": 3688 } }, { @@ -1544,8 +1544,8 @@ "rule": "prog2-to-progn", "severity": "warning", "span": { - "end": 5947, - "start": 5928 + "end": 3753, + "start": 3730 } }, { @@ -1557,8 +1557,8 @@ "rule": "handler-case-no-clauses", "severity": "warning", "span": { - "end": 6017, - "start": 5997 + "end": 3792, + "start": 3772 } }, { @@ -1570,8 +1570,8 @@ "rule": "unwind-protect-no-cleanup", "severity": "warning", "span": { - "end": 6097, - "start": 6075 + "end": 3842, + "start": 3820 } }, { @@ -1583,8 +1583,8 @@ "rule": "redundant-start-zero", "severity": "warning", "span": { - "end": 4288, - "start": 4265 + "end": 2636, + "start": 2613 } }, { @@ -1596,8 +1596,8 @@ "rule": "redundant-end-nil", "severity": "warning", "span": { - "end": 4363, - "start": 4340 + "end": 2684, + "start": 2661 } }, { @@ -1609,8 +1609,8 @@ "rule": "redundant-from-end-nil", "severity": "warning", "span": { - "end": 4440, - "start": 4412 + "end": 2734, + "start": 2706 } }, { @@ -1622,8 +1622,8 @@ "rule": "redundant-count-nil", "severity": "warning", "span": { - "end": 4516, - "start": 4489 + "end": 2788, + "start": 2761 } }, { @@ -1635,8 +1635,8 @@ "rule": "string-case-fold", "severity": "warning", "span": { - "end": 4614, - "start": 4563 + "end": 2863, + "start": 2812 } }, { @@ -1648,8 +1648,8 @@ "rule": "char-case-fold", "severity": "warning", "span": { - "end": 4679, - "start": 4634 + "end": 2929, + "start": 2884 } }, { @@ -1661,8 +1661,8 @@ "rule": "nested-string-case", "severity": "warning", "span": { - "end": 4740, - "start": 4703 + "end": 2985, + "start": 2948 } }, { @@ -1674,8 +1674,8 @@ "rule": "code-char-char-code", "severity": "warning", "span": { - "end": 4803, - "start": 4776 + "end": 3035, + "start": 3008 } }, { @@ -1687,8 +1687,8 @@ "rule": "last-default-count", "severity": "warning", "span": { - "end": 4862, - "start": 4850 + "end": 3071, + "start": 3059 } }, { @@ -1700,8 +1700,8 @@ "rule": "butlast-default-count", "severity": "warning", "span": { - "end": 4938, - "start": 4923 + "end": 3109, + "start": 3094 } }, { @@ -1713,8 +1713,8 @@ "rule": "make-list-default-element", "severity": "warning", "span": { - "end": 5035, - "start": 4999 + "end": 3171, + "start": 3135 } }, { @@ -1726,8 +1726,8 @@ "rule": "parse-integer-default-radix", "severity": "warning", "span": { - "end": 5108, - "start": 5079 + "end": 3230, + "start": 3201 } }, { @@ -1739,8 +1739,8 @@ "rule": "getf-default-nil", "severity": "warning", "span": { - "end": 5180, - "start": 5161 + "end": 3281, + "start": 3262 } }, { @@ -1752,8 +1752,8 @@ "rule": "make-array-default-keyword", "severity": "warning", "span": { - "end": 5265, - "start": 5232 + "end": 3335, + "start": 3302 } }, { @@ -1765,8 +1765,8 @@ "rule": "nested-char-case", "severity": "warning", "span": { - "end": 5346, - "start": 5313 + "end": 3399, + "start": 3366 } }, { @@ -1778,8 +1778,8 @@ "rule": "list-star-nil", "severity": "warning", "span": { - "end": 5405, - "start": 5384 + "end": 3441, + "start": 3420 } }, { @@ -1791,7 +1791,7 @@ "rule": "declarative-style-score", "severity": "warning", "span": { - "end": 10167, + "end": 6775, "start": 0 } }, @@ -1804,8 +1804,8 @@ "rule": "leftover-print-debug", "severity": "warning", "span": { - "end": 8873, - "start": 8864 + "end": 5806, + "start": 5797 } }, { @@ -1817,8 +1817,8 @@ "rule": "defpackage-without-in-package", "severity": "warning", "span": { - "end": 10063, - "start": 10031 + "end": 6724, + "start": 6692 } }, { @@ -1830,8 +1830,8 @@ "rule": "return-from-unmatched-block", "severity": "warning", "span": { - "end": 2941, - "start": 2920 + "end": 1883, + "start": 1860 } }, { @@ -1843,8 +1843,8 @@ "rule": "unused-local-binding", "severity": "warning", "span": { - "end": 8638, - "start": 8637 + "end": 5606, + "start": 5605 } }, { @@ -1856,8 +1856,8 @@ "rule": "unused-local-binding", "severity": "warning", "span": { - "end": 8644, - "start": 8643 + "end": 5618, + "start": 5617 } } ], diff --git a/tests/fixtures/lint_golden/expected/broad.sarif.golden b/tests/fixtures/lint_golden/expected/broad.sarif.golden index 3020c08d4..8a4fcaf16 100644 --- a/tests/fixtures/lint_golden/expected/broad.sarif.golden +++ b/tests/fixtures/lint_golden/expected/broad.sarif.golden @@ -13,9 +13,9 @@ }, "region": { "byteLength": 10, - "byteOffset": 6875, + "byteOffset": 4273, "startColumn": 1, - "startLine": 99 + "startLine": 234 } } } @@ -25,7 +25,7 @@ }, "partialFingerprints": { "pareditFindingId": "self-assignment/5f1a5b802aa99b47/0", - "primaryLocationLineHash": "fnv1a64:3090b4323101cc12:0" + "primaryLocationLineHash": "fnv1a64:937cae6f165b9c98:0" }, "ruleId": "self-assignment" }, @@ -38,10 +38,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 22, - "byteOffset": 6961, - "startColumn": 17, - "startLine": 100 + "byteLength": 30, + "byteOffset": 4321, + "startColumn": 3, + "startLine": 237 } } } @@ -51,7 +51,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-setf-places/8104810ed815b9fd/0", - "primaryLocationLineHash": "fnv1a64:dec66b63172ec399:0" + "primaryLocationLineHash": "fnv1a64:e369aac3bd876808:0" }, "ruleId": "duplicate-setf-places" }, @@ -64,10 +64,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 26, - "byteOffset": 7021, + "byteLength": 32, + "byteOffset": 4378, "startColumn": 1, - "startLine": 101 + "startLine": 240 } } } @@ -77,7 +77,7 @@ }, "partialFingerprints": { "pareditFindingId": "setf-arity/b0a5b422aad6d4d2/0", - "primaryLocationLineHash": "fnv1a64:adc9c4e54f1f85e9:0" + "primaryLocationLineHash": "fnv1a64:922f99954220a3ac:0" }, "ruleId": "setf-arity" }, @@ -91,9 +91,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 7092, + "byteOffset": 4431, "startColumn": 7, - "startLine": 102 + "startLine": 243 } } } @@ -103,7 +103,7 @@ }, "partialFingerprints": { "pareditFindingId": "setq-non-variable/93a38b0abb06fba2/0", - "primaryLocationLineHash": "fnv1a64:961b4a0b9146b6e8:0" + "primaryLocationLineHash": "fnv1a64:ecd08edfe345c3da:0" }, "ruleId": "setq-non-variable" }, @@ -119,7 +119,7 @@ { "deletedRegion": { "byteLength": 19, - "byteOffset": 3644 + "byteOffset": 2282 }, "insertedContent": { "text": "(incf ctr)" @@ -142,9 +142,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 3644, + "byteOffset": 2282, "startColumn": 1, - "startLine": 53 + "startLine": 129 } } } @@ -154,7 +154,7 @@ }, "partialFingerprints": { "pareditFindingId": "manual-incf/e9cc51bb9767dcb7/0", - "primaryLocationLineHash": "fnv1a64:5a5c0c1b982a0284:0" + "primaryLocationLineHash": "fnv1a64:4ad9688e6f349584:0" }, "ruleId": "manual-incf" }, @@ -170,7 +170,7 @@ { "deletedRegion": { "byteLength": 23, - "byteOffset": 3710 + "byteOffset": 2317 }, "insertedContent": { "text": "(push e lst)" @@ -193,9 +193,9 @@ }, "region": { "byteLength": 23, - "byteOffset": 3710, + "byteOffset": 2317, "startColumn": 1, - "startLine": 54 + "startLine": 131 } } } @@ -205,7 +205,7 @@ }, "partialFingerprints": { "pareditFindingId": "manual-push/4847791ff6aa61f5/0", - "primaryLocationLineHash": "fnv1a64:f629ef340a844646:0" + "primaryLocationLineHash": "fnv1a64:95b9befebdc339e6:0" }, "ruleId": "manual-push" }, @@ -221,7 +221,7 @@ { "deletedRegion": { "byteLength": 23, - "byteOffset": 3776 + "byteOffset": 2356 }, "insertedContent": { "text": "(pushnew e st)" @@ -244,9 +244,9 @@ }, "region": { "byteLength": 23, - "byteOffset": 3776, + "byteOffset": 2356, "startColumn": 1, - "startLine": 55 + "startLine": 133 } } } @@ -256,7 +256,7 @@ }, "partialFingerprints": { "pareditFindingId": "manual-pushnew/1e8f91739c283b2f/0", - "primaryLocationLineHash": "fnv1a64:6a5dce420c660fe8:0" + "primaryLocationLineHash": "fnv1a64:af5a2ffbbc06e4c8:0" }, "ruleId": "manual-pushnew" }, @@ -272,7 +272,7 @@ { "deletedRegion": { "byteLength": 14, - "byteOffset": 2773 + "byteOffset": 1786 }, "insertedContent": { "text": "(incf tally)" @@ -295,9 +295,9 @@ }, "region": { "byteLength": 14, - "byteOffset": 2773, + "byteOffset": 1786, "startColumn": 1, - "startLine": 41 + "startLine": 97 } } } @@ -307,7 +307,7 @@ }, "partialFingerprints": { "pareditFindingId": "explicit-step-delta/00a1f8d32f2b1a3f/0", - "primaryLocationLineHash": "fnv1a64:a6f6582f9595e57e:0" + "primaryLocationLineHash": "fnv1a64:13ed20ccc0bc217c:0" }, "ruleId": "explicit-step-delta" }, @@ -323,7 +323,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 2847 + "byteOffset": 1824 }, "insertedContent": { "text": "(decf nsd 3)" @@ -346,9 +346,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 2847, + "byteOffset": 1824, "startColumn": 1, - "startLine": 42 + "startLine": 99 } } } @@ -358,7 +358,7 @@ }, "partialFingerprints": { "pareditFindingId": "negated-step-delta/c72d843010c3cb77/0", - "primaryLocationLineHash": "fnv1a64:653c09f0cd0befce:0" + "primaryLocationLineHash": "fnv1a64:16866cf820b2cb06:0" }, "ruleId": "negated-step-delta" }, @@ -373,8 +373,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 21, - "byteOffset": 2920 + "byteLength": 23, + "byteOffset": 1860 }, "insertedContent": { "text": "(return-from blk)" @@ -396,10 +396,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 21, - "byteOffset": 2920, + "byteLength": 23, + "byteOffset": 1860, "startColumn": 1, - "startLine": 43 + "startLine": 101 } } } @@ -409,7 +409,7 @@ }, "partialFingerprints": { "pareditFindingId": "explicit-nil-return/83c6c0866319952f/0", - "primaryLocationLineHash": "fnv1a64:4a60f7a86f540560:0" + "primaryLocationLineHash": "fnv1a64:960ae5beeac85c8c:0" }, "ruleId": "explicit-nil-return" }, @@ -425,7 +425,7 @@ { "deletedRegion": { "byteLength": 12, - "byteOffset": 1223 + "byteOffset": 916 }, "insertedContent": { "text": "(list e)" @@ -448,9 +448,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 1223, + "byteOffset": 916, "startColumn": 1, - "startLine": 19 + "startLine": 47 } } } @@ -460,7 +460,7 @@ }, "partialFingerprints": { "pareditFindingId": "cons-to-list/30734641edf18c29/0", - "primaryLocationLineHash": "fnv1a64:92886f9c57c080aa:0" + "primaryLocationLineHash": "fnv1a64:4b1f362be758ec88:0" }, "ruleId": "cons-to-list" }, @@ -476,7 +476,7 @@ { "deletedRegion": { "byteLength": 22, - "byteOffset": 1290 + "byteOffset": 945 }, "insertedContent": { "text": "(copy-seq dr)" @@ -499,9 +499,9 @@ }, "region": { "byteLength": 22, - "byteOffset": 1290, + "byteOffset": 945, "startColumn": 1, - "startLine": 20 + "startLine": 49 } } } @@ -511,7 +511,7 @@ }, "partialFingerprints": { "pareditFindingId": "double-reverse/64abc2d4def62155/0", - "primaryLocationLineHash": "fnv1a64:ef22f2138a3df6ca:0" + "primaryLocationLineHash": "fnv1a64:86aac9418b8d9904:0" }, "ruleId": "double-reverse" }, @@ -525,9 +525,9 @@ }, "region": { "byteLength": 18, - "byteOffset": 7158, + "byteOffset": 4463, "startColumn": 1, - "startLine": 103 + "startLine": 245 } } } @@ -537,7 +537,7 @@ }, "partialFingerprints": { "pareditFindingId": "modify-macro-arity/1c9711db871ff5e7/0", - "primaryLocationLineHash": "fnv1a64:ffb1d94fba73bf2e:0" + "primaryLocationLineHash": "fnv1a64:b6c9e79d7a681282:0" }, "ruleId": "modify-macro-arity" }, @@ -550,10 +550,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 44, - "byteOffset": 7231, + "byteLength": 46, + "byteOffset": 4504, "startColumn": 1, - "startLine": 104 + "startLine": 247 } } } @@ -563,7 +563,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-parameters/fc20fd38e853fe41/0", - "primaryLocationLineHash": "fnv1a64:f231a6cd2f17e63a:0" + "primaryLocationLineHash": "fnv1a64:7edcf7a89269afbe:0" }, "ruleId": "duplicate-parameters" }, @@ -576,10 +576,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 41, - "byteOffset": 7306, + "byteLength": 43, + "byteOffset": 4575, "startColumn": 1, - "startLine": 105 + "startLine": 250 } } } @@ -589,7 +589,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-lambda-list-keyword/2f60a48b9e4ef7e3/0", - "primaryLocationLineHash": "fnv1a64:898223a354d25b28:0" + "primaryLocationLineHash": "fnv1a64:db8d897dd15bad8e:0" }, "ruleId": "duplicate-lambda-list-keyword" }, @@ -602,10 +602,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 38, - "byteOffset": 7390, + "byteLength": 40, + "byteOffset": 4652, "startColumn": 1, - "startLine": 106 + "startLine": 253 } } } @@ -615,7 +615,7 @@ }, "partialFingerprints": { "pareditFindingId": "lambda-list-keyword-order/617c0a49865251a2/0", - "primaryLocationLineHash": "fnv1a64:60b6533ac07ce5c9:0" + "primaryLocationLineHash": "fnv1a64:64e44b51bed932e3:0" }, "ruleId": "lambda-list-keyword-order" }, @@ -631,7 +631,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 438 + "byteOffset": 437 }, "insertedContent": { "text": "5" @@ -654,9 +654,9 @@ }, "region": { "byteLength": 2, - "byteOffset": 438, + "byteOffset": 437, "startColumn": 7, - "startLine": 8 + "startLine": 7 } } } @@ -666,7 +666,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-quote/07bb8307b4864109/0", - "primaryLocationLineHash": "fnv1a64:f55478ae60504a63:0" + "primaryLocationLineHash": "fnv1a64:f52fbd732150ff13:0" }, "ruleId": "redundant-quote" }, @@ -681,8 +681,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 12, - "byteOffset": 502 + "byteLength": 14, + "byteOffset": 460 }, "insertedContent": { "text": "only" @@ -704,8 +704,8 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 12, - "byteOffset": 502, + "byteLength": 14, + "byteOffset": 460, "startColumn": 1, "startLine": 9 } @@ -717,7 +717,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-progn/a2fdba9820c97822/0", - "primaryLocationLineHash": "fnv1a64:16a6524ab05ba619:0" + "primaryLocationLineHash": "fnv1a64:8b06e00bd2adf89b:0" }, "ruleId": "redundant-progn" }, @@ -732,11 +732,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 11, - "byteOffset": 581 + "byteLength": 19, + "byteOffset": 507 }, "insertedContent": { - "text": "b c" + "text": "b\n c" } } ] @@ -755,10 +755,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 11, - "byteOffset": 581, - "startColumn": 10, - "startLine": 10 + "byteLength": 19, + "byteOffset": 507, + "startColumn": 3, + "startLine": 14 } } } @@ -768,7 +768,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-progn/5cd55ce143529b1f/0", - "primaryLocationLineHash": "fnv1a64:5ecf422cc5677c46:0" + "primaryLocationLineHash": "fnv1a64:237c01a0c789050b:0" }, "ruleId": "nested-progn" }, @@ -783,8 +783,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 24, - "byteOffset": 3135 + "byteLength": 30, + "byteOffset": 2004 }, "insertedContent": { "text": "(when (and wa wb) (wc))" @@ -806,10 +806,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 24, - "byteOffset": 3135, + "byteLength": 30, + "byteOffset": 2004, "startColumn": 1, - "startLine": 46 + "startLine": 109 } } } @@ -819,7 +819,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-when/3709b9f1558a096d/0", - "primaryLocationLineHash": "fnv1a64:860a5bc0c11ea718:0" + "primaryLocationLineHash": "fnv1a64:27a7debe0372bafd:0" }, "ruleId": "nested-when" }, @@ -834,8 +834,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 28, - "byteOffset": 3201 + "byteLength": 34, + "byteOffset": 2050 }, "insertedContent": { "text": "(unless (or ua ub) (uc))" @@ -857,10 +857,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 28, - "byteOffset": 3201, + "byteLength": 34, + "byteOffset": 2050, "startColumn": 1, - "startLine": 47 + "startLine": 113 } } } @@ -870,7 +870,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-unless/374f1c05f4fd74ef/0", - "primaryLocationLineHash": "fnv1a64:b12f2e1b4f562872:0" + "primaryLocationLineHash": "fnv1a64:632a63e510e89843:0" }, "ruleId": "nested-unless" }, @@ -886,7 +886,7 @@ { "deletedRegion": { "byteLength": 10, - "byteOffset": 3073 + "byteOffset": 1974 }, "insertedContent": { "text": "pb qc" @@ -909,9 +909,9 @@ }, "region": { "byteLength": 10, - "byteOffset": 3073, + "byteOffset": 1974, "startColumn": 8, - "startLine": 45 + "startLine": 107 } } } @@ -921,7 +921,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-boolean/62bd4b586d0045bf/0", - "primaryLocationLineHash": "fnv1a64:becd738b2f54a859:0" + "primaryLocationLineHash": "fnv1a64:61f4f69082012eb1:0" }, "ruleId": "nested-boolean" }, @@ -937,7 +937,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 3845 + "byteOffset": 2398 }, "insertedContent": { "text": "(cadr z)" @@ -960,9 +960,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 3845, + "byteOffset": 2398, "startColumn": 1, - "startLine": 56 + "startLine": 135 } } } @@ -972,7 +972,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-cxr/109a80ae72e5eb4e/0", - "primaryLocationLineHash": "fnv1a64:6950a74d950cd247:0" + "primaryLocationLineHash": "fnv1a64:d1781131b8b811af:0" }, "ruleId": "nested-cxr" }, @@ -988,7 +988,7 @@ { "deletedRegion": { "byteLength": 10, - "byteOffset": 3910 + "byteOffset": 2426 }, "insertedContent": { "text": "(first zs)" @@ -1011,9 +1011,9 @@ }, "region": { "byteLength": 10, - "byteOffset": 3910, + "byteOffset": 2426, "startColumn": 1, - "startLine": 57 + "startLine": 137 } } } @@ -1023,7 +1023,7 @@ }, "partialFingerprints": { "pareditFindingId": "nth-constant-index/9c4d78c87d9ad119/0", - "primaryLocationLineHash": "fnv1a64:713b5762fbc57522:0" + "primaryLocationLineHash": "fnv1a64:92f31e88b94d0434:0" }, "ruleId": "nth-constant-index" }, @@ -1039,7 +1039,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 3983 + "byteOffset": 2459 }, "insertedContent": { "text": "nz" @@ -1062,9 +1062,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 3983, + "byteOffset": 2459, "startColumn": 1, - "startLine": 58 + "startLine": 139 } } } @@ -1074,7 +1074,7 @@ }, "partialFingerprints": { "pareditFindingId": "nthcdr-zero/bfda713e07890a09/0", - "primaryLocationLineHash": "fnv1a64:12a7637d498d9262:0" + "primaryLocationLineHash": "fnv1a64:c6d5daeaca72f8aa:0" }, "ruleId": "nthcdr-zero" }, @@ -1090,7 +1090,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 4049 + "byteOffset": 2488 }, "insertedContent": { "text": "(cddr ns)" @@ -1113,9 +1113,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 4049, + "byteOffset": 2488, "startColumn": 1, - "startLine": 59 + "startLine": 141 } } } @@ -1125,7 +1125,7 @@ }, "partialFingerprints": { "pareditFindingId": "nthcdr-small-index/f273b4ffe8359de6/0", - "primaryLocationLineHash": "fnv1a64:2bdf34280b5d4185:0" + "primaryLocationLineHash": "fnv1a64:1e089bc9cb6239a5:0" }, "ruleId": "nthcdr-small-index" }, @@ -1140,11 +1140,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 11, - "byteOffset": 665 + "byteLength": 19, + "byteOffset": 572 }, "insertedContent": { - "text": "s t" + "text": "s\n t" } } ] @@ -1163,10 +1163,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 11, - "byteOffset": 665, - "startColumn": 9, - "startLine": 11 + "byteLength": 19, + "byteOffset": 572, + "startColumn": 3, + "startLine": 19 } } } @@ -1176,7 +1176,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-body-progn/bd91eb5e515cc145/0", - "primaryLocationLineHash": "fnv1a64:b77e04695f87ff9c:0" + "primaryLocationLineHash": "fnv1a64:610ff84ec923f832:0" }, "ruleId": "redundant-body-progn" }, @@ -1192,7 +1192,7 @@ { "deletedRegion": { "byteLength": 7, - "byteOffset": 732 + "byteOffset": 617 }, "insertedContent": { "text": "(progn" @@ -1214,10 +1214,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 20, - "byteOffset": 732, + "byteLength": 24, + "byteOffset": 617, "startColumn": 1, - "startLine": 12 + "startLine": 23 } } } @@ -1227,7 +1227,7 @@ }, "partialFingerprints": { "pareditFindingId": "empty-let/6f975d0b4722f4eb/0", - "primaryLocationLineHash": "fnv1a64:2f45ac0b02ff3fa6:0" + "primaryLocationLineHash": "fnv1a64:5ead522e3c909d98:0" }, "ruleId": "empty-let" }, @@ -1242,8 +1242,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 4, - "byteOffset": 803 + "byteLength": 8, + "byteOffset": 666 }, "insertedContent": { "text": "" @@ -1265,10 +1265,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 12, - "byteOffset": 796, + "byteLength": 20, + "byteOffset": 655, "startColumn": 1, - "startLine": 13 + "startLine": 27 } } } @@ -1278,7 +1278,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-if-nil/e883c2a7438b14d9/0", - "primaryLocationLineHash": "fnv1a64:d7e58f51fda42304:0" + "primaryLocationLineHash": "fnv1a64:b7b2f9c2e345a494:0" }, "ruleId": "redundant-if-nil" }, @@ -1294,7 +1294,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 2560 + "byteOffset": 1656 }, "insertedContent": { "text": "let" @@ -1316,10 +1316,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 16, - "byteOffset": 2559, + "byteLength": 18, + "byteOffset": 1655, "startColumn": 1, - "startLine": 38 + "startLine": 86 } } } @@ -1329,7 +1329,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-let-star/a18f256659e1ba9a/0", - "primaryLocationLineHash": "fnv1a64:ff3b2ae8c5f74a89:0" + "primaryLocationLineHash": "fnv1a64:6e0f0e235f872590:0" }, "ruleId": "redundant-let-star" }, @@ -1345,7 +1345,7 @@ { "deletedRegion": { "byteLength": 10, - "byteOffset": 868 + "byteOffset": 697 }, "insertedContent": { "text": "" @@ -1368,9 +1368,9 @@ }, "region": { "byteLength": 15, - "byteOffset": 867, + "byteOffset": 696, "startColumn": 1, - "startLine": 14 + "startLine": 31 } } } @@ -1380,7 +1380,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-funcall/80c1c3159cdf3d87/0", - "primaryLocationLineHash": "fnv1a64:baf4cdcef2e2549c:0" + "primaryLocationLineHash": "fnv1a64:2b41a17b8f18089c:0" }, "ruleId": "redundant-funcall" }, @@ -1396,7 +1396,7 @@ { "deletedRegion": { "byteLength": 16, - "byteOffset": 939 + "byteOffset": 733 }, "insertedContent": { "text": "whatever" @@ -1419,9 +1419,9 @@ }, "region": { "byteLength": 16, - "byteOffset": 939, + "byteOffset": 733, "startColumn": 1, - "startLine": 15 + "startLine": 33 } } } @@ -1431,7 +1431,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-the/2bac242fe26b506b/0", - "primaryLocationLineHash": "fnv1a64:e01d638688c7bec2:0" + "primaryLocationLineHash": "fnv1a64:454a071776dd9032:0" }, "ruleId": "redundant-the" }, @@ -1446,8 +1446,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 8, - "byteOffset": 1008 + "byteLength": 9, + "byteOffset": 768 }, "insertedContent": { "text": "" @@ -1469,10 +1469,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 28, - "byteOffset": 1007, + "byteLength": 33, + "byteOffset": 767, "startColumn": 1, - "startLine": 16 + "startLine": 35 } } } @@ -1482,7 +1482,7 @@ }, "partialFingerprints": { "pareditFindingId": "funcall-lambda/673d7cfe29eecb61/0", - "primaryLocationLineHash": "fnv1a64:da55f61fad0f3668:0" + "primaryLocationLineHash": "fnv1a64:85b1f6e1d6531da5:0" }, "ruleId": "funcall-lambda" }, @@ -1497,11 +1497,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 18, - "byteOffset": 1084 + "byteLength": 23, + "byteOffset": 828 }, "insertedContent": { - "text": "(lambda (sq) sq)" + "text": "(lambda (sq)\n sq)" } } ] @@ -1520,10 +1520,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 18, - "byteOffset": 1084, - "startColumn": 9, - "startLine": 17 + "byteLength": 23, + "byteOffset": 828, + "startColumn": 2, + "startLine": 41 } } } @@ -1533,7 +1533,7 @@ }, "partialFingerprints": { "pareditFindingId": "sharp-quoted-lambda/8265b306d04d5a6a/0", - "primaryLocationLineHash": "fnv1a64:3f3939cd32da23b1:0" + "primaryLocationLineHash": "fnv1a64:c8a74208e8fac938:0" }, "ruleId": "sharp-quoted-lambda" }, @@ -1549,7 +1549,7 @@ { "deletedRegion": { "byteLength": 12, - "byteOffset": 1150 + "byteOffset": 881 }, "insertedContent": { "text": "h" @@ -1572,9 +1572,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 1150, + "byteOffset": 881, "startColumn": 1, - "startLine": 18 + "startLine": 45 } } } @@ -1584,7 +1584,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-identity/05affcb5b7734a90/0", - "primaryLocationLineHash": "fnv1a64:1c26f1905316a18f:0" + "primaryLocationLineHash": "fnv1a64:b69f39f23cf16d1b:0" }, "ruleId": "redundant-identity" }, @@ -1600,7 +1600,7 @@ { "deletedRegion": { "byteLength": 20, - "byteOffset": 4122 + "byteOffset": 2524 }, "insertedContent": { "text": "(g m)" @@ -1623,9 +1623,9 @@ }, "region": { "byteLength": 20, - "byteOffset": 4122, + "byteOffset": 2524, "startColumn": 1, - "startLine": 60 + "startLine": 143 } } } @@ -1635,7 +1635,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-apply/f5c33aecf2ade963/0", - "primaryLocationLineHash": "fnv1a64:f541798a5705fb96:0" + "primaryLocationLineHash": "fnv1a64:0d293b096033f424:0" }, "ruleId": "redundant-apply" }, @@ -1651,7 +1651,7 @@ { "deletedRegion": { "byteLength": 12, - "byteOffset": 4205 + "byteOffset": 2577 }, "insertedContent": { "text": "" @@ -1674,9 +1674,9 @@ }, "region": { "byteLength": 26, - "byteOffset": 4192, + "byteOffset": 2564, "startColumn": 1, - "startLine": 61 + "startLine": 145 } } } @@ -1686,7 +1686,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-eql-test/08921075042be6dd/0", - "primaryLocationLineHash": "fnv1a64:954f815ba503034c:0" + "primaryLocationLineHash": "fnv1a64:75e9850ffd56ad98:0" }, "ruleId": "redundant-eql-test" }, @@ -1702,7 +1702,7 @@ { "deletedRegion": { "byteLength": 16, - "byteOffset": 5465 + "byteOffset": 3472 }, "insertedContent": { "text": "" @@ -1725,9 +1725,9 @@ }, "region": { "byteLength": 30, - "byteOffset": 5452, + "byteOffset": 3459, "startColumn": 1, - "startLine": 78 + "startLine": 179 } } } @@ -1737,7 +1737,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-identity-key/0d6a3e2540c960d7/0", - "primaryLocationLineHash": "fnv1a64:18bb3da3ff50f4cc:0" + "primaryLocationLineHash": "fnv1a64:c400ef0fc6539cf2:0" }, "ruleId": "redundant-identity-key" }, @@ -1753,7 +1753,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 3504 + "byteOffset": 2212 }, "insertedContent": { "text": "unless" @@ -1762,7 +1762,7 @@ { "deletedRegion": { "byteLength": 7, - "byteOffset": 3509 + "byteOffset": 2217 }, "insertedContent": { "text": "r" @@ -1784,10 +1784,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 16, - "byteOffset": 3503, + "byteLength": 18, + "byteOffset": 2211, "startColumn": 1, - "startLine": 51 + "startLine": 123 } } } @@ -1797,7 +1797,7 @@ }, "partialFingerprints": { "pareditFindingId": "negated-when-unless/8cea77f08ec45975/0", - "primaryLocationLineHash": "fnv1a64:ba0d1f7e3afd3954:0" + "primaryLocationLineHash": "fnv1a64:2b372b14990f6ded:0" }, "ruleId": "negated-when-unless" }, @@ -1813,7 +1813,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 5599 + "byteOffset": 3547 }, "insertedContent": { "text": "(>= a b)" @@ -1836,9 +1836,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 5599, + "byteOffset": 3547, "startColumn": 1, - "startLine": 80 + "startLine": 183 } } } @@ -1848,7 +1848,7 @@ }, "partialFingerprints": { "pareditFindingId": "negated-comparison/63ee3702a87c2d97/0", - "primaryLocationLineHash": "fnv1a64:3a77f06c38b9c956:0" + "primaryLocationLineHash": "fnv1a64:42d59db6cfd3613e:0" }, "ruleId": "negated-comparison" }, @@ -1863,8 +1863,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 16, - "byteOffset": 5672 + "byteLength": 24, + "byteOffset": 3583 }, "insertedContent": { "text": "(if c b a)" @@ -1886,10 +1886,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 16, - "byteOffset": 5672, + "byteLength": 24, + "byteOffset": 3583, "startColumn": 1, - "startLine": 81 + "startLine": 185 } } } @@ -1899,7 +1899,7 @@ }, "partialFingerprints": { "pareditFindingId": "negated-if/33df133ba8537bf9/0", - "primaryLocationLineHash": "fnv1a64:5d377dbd261def62:0" + "primaryLocationLineHash": "fnv1a64:2d1e58630d7b0515:0" }, "ruleId": "negated-if" }, @@ -1914,8 +1914,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 13, - "byteOffset": 5737 + "byteLength": 21, + "byteOffset": 3622 }, "insertedContent": { "text": "(or iv jv)" @@ -1937,10 +1937,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 13, - "byteOffset": 5737, + "byteLength": 21, + "byteOffset": 3622, "startColumn": 1, - "startLine": 82 + "startLine": 189 } } } @@ -1950,7 +1950,7 @@ }, "partialFingerprints": { "pareditFindingId": "if-to-or/ab61c84ad573df95/0", - "primaryLocationLineHash": "fnv1a64:439a5168093cfcae:0" + "primaryLocationLineHash": "fnv1a64:7d8356fa43277d1a:0" }, "ruleId": "if-to-or" }, @@ -1965,8 +1965,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 13, - "byteOffset": 5800 + "byteLength": 21, + "byteOffset": 3656 }, "insertedContent": { "text": "(not iw)" @@ -1988,10 +1988,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 13, - "byteOffset": 5800, + "byteLength": 21, + "byteOffset": 3656, "startColumn": 1, - "startLine": 83 + "startLine": 193 } } } @@ -2001,7 +2001,7 @@ }, "partialFingerprints": { "pareditFindingId": "if-not/62237ccefbf0b61e/0", - "primaryLocationLineHash": "fnv1a64:7b9908e9c81e94cb:0" + "primaryLocationLineHash": "fnv1a64:c8ef3af364e97075:0" }, "ruleId": "if-not" }, @@ -2017,7 +2017,7 @@ { "deletedRegion": { "byteLength": 9, - "byteOffset": 6155 + "byteOffset": 3872 }, "insertedContent": { "text": "(1+ osa)" @@ -2040,9 +2040,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 6155, + "byteOffset": 3872, "startColumn": 1, - "startLine": 88 + "startLine": 209 } } } @@ -2052,7 +2052,7 @@ }, "partialFingerprints": { "pareditFindingId": "one-step-arithmetic/044bc8cb6d37fb31/0", - "primaryLocationLineHash": "fnv1a64:4c45b639d0c24ada:0" + "primaryLocationLineHash": "fnv1a64:8d1b5e2a8a55c9d2:0" }, "ruleId": "one-step-arithmetic" }, @@ -2068,7 +2068,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 3578 + "byteOffset": 2254 }, "insertedContent": { "text": "when" @@ -2090,10 +2090,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 8, - "byteOffset": 3577, + "byteLength": 12, + "byteOffset": 2253, "startColumn": 1, - "startLine": 52 + "startLine": 126 } } } @@ -2103,7 +2103,7 @@ }, "partialFingerprints": { "pareditFindingId": "one-armed-if/efd043892749780a/0", - "primaryLocationLineHash": "fnv1a64:c611145142b55185:0" + "primaryLocationLineHash": "fnv1a64:8eee6de9d82e904a:0" }, "ruleId": "one-armed-if" }, @@ -2117,9 +2117,9 @@ }, "region": { "byteLength": 18, - "byteOffset": 7476, + "byteOffset": 4728, "startColumn": 7, - "startLine": 107 + "startLine": 256 } } } @@ -2129,7 +2129,7 @@ }, "partialFingerprints": { "pareditFindingId": "self-comparison/448235d114bbed7c/0", - "primaryLocationLineHash": "fnv1a64:aa2528fc94277c15:0" + "primaryLocationLineHash": "fnv1a64:4f8255d15ceed382:0" }, "ruleId": "self-comparison" }, @@ -2145,7 +2145,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 6518 + "byteOffset": 4062 }, "insertedContent": { "text": "(null w)" @@ -2168,9 +2168,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 6518, + "byteOffset": 4062, "startColumn": 1, - "startLine": 93 + "startLine": 222 } } } @@ -2180,7 +2180,7 @@ }, "partialFingerprints": { "pareditFindingId": "nil-comparison/826bacda3f3e61e2/0", - "primaryLocationLineHash": "fnv1a64:cee862a953ed938b:0" + "primaryLocationLineHash": "fnv1a64:c9798a47b12196c3:0" }, "ruleId": "nil-comparison" }, @@ -2194,9 +2194,9 @@ }, "region": { "byteLength": 18, - "byteOffset": 7558, - "startColumn": 19, - "startLine": 108 + "byteOffset": 4791, + "startColumn": 3, + "startLine": 260 } } } @@ -2206,7 +2206,7 @@ }, "partialFingerprints": { "pareditFindingId": "t-comparison/5e76896e21ed7ee4/0", - "primaryLocationLineHash": "fnv1a64:cbc3239c54512777:0" + "primaryLocationLineHash": "fnv1a64:e7def32533ac17b2:0" }, "ruleId": "t-comparison" }, @@ -2219,10 +2219,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 25, - "byteOffset": 7607, + "byteLength": 33, + "byteOffset": 4827, "startColumn": 1, - "startLine": 109 + "startLine": 262 } } } @@ -2232,7 +2232,7 @@ }, "partialFingerprints": { "pareditFindingId": "identical-if-branches/5ea1ac8de34ee4b7/0", - "primaryLocationLineHash": "fnv1a64:96e9fc2b041f8884:0" + "primaryLocationLineHash": "fnv1a64:013209230f5f679e:0" }, "ruleId": "identical-if-branches" }, @@ -2247,8 +2247,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 13, - "byteOffset": 6229 + "byteLength": 21, + "byteOffset": 3905 }, "insertedContent": { "text": "on" @@ -2270,10 +2270,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 13, - "byteOffset": 6229, + "byteLength": 21, + "byteOffset": 3905, "startColumn": 1, - "startLine": 89 + "startLine": 211 } } } @@ -2283,7 +2283,7 @@ }, "partialFingerprints": { "pareditFindingId": "constant-if-test/026b11490469946b/0", - "primaryLocationLineHash": "fnv1a64:40ec4efff8b28494:0" + "primaryLocationLineHash": "fnv1a64:084de9c82365d0df:0" }, "ruleId": "constant-if-test" }, @@ -2299,7 +2299,7 @@ { "deletedRegion": { "byteLength": 7, - "byteOffset": 6300 + "byteOffset": 3947 }, "insertedContent": { "text": "(progn" @@ -2321,10 +2321,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 13, - "byteOffset": 6300, + "byteLength": 15, + "byteOffset": 3947, "startColumn": 1, - "startLine": 90 + "startLine": 215 } } } @@ -2334,7 +2334,7 @@ }, "partialFingerprints": { "pareditFindingId": "constant-when-test/9b0a7978fb01361b/0", - "primaryLocationLineHash": "fnv1a64:19e72980000a867e:0" + "primaryLocationLineHash": "fnv1a64:208acf2163b05f31:0" }, "ruleId": "constant-when-test" }, @@ -2347,10 +2347,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 12, - "byteOffset": 6735, + "byteLength": 24, + "byteOffset": 4160, "startColumn": 1, - "startLine": 96 + "startLine": 228 } } } @@ -2360,7 +2360,7 @@ }, "partialFingerprints": { "pareditFindingId": "if-arity/312e6de6292b7113/0", - "primaryLocationLineHash": "fnv1a64:18d463927d801823:0" + "primaryLocationLineHash": "fnv1a64:d310ceaabd92b0f8:0" }, "ruleId": "if-arity" }, @@ -2374,9 +2374,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 7683, + "byteOffset": 4886, "startColumn": 1, - "startLine": 110 + "startLine": 266 } } } @@ -2386,7 +2386,7 @@ }, "partialFingerprints": { "pareditFindingId": "the-arity/1898bfc17b742eda/0", - "primaryLocationLineHash": "fnv1a64:0ac530374b9a022d:0" + "primaryLocationLineHash": "fnv1a64:282e46a03e91fd93:0" }, "ruleId": "the-arity" }, @@ -2400,9 +2400,9 @@ }, "region": { "byteLength": 6, - "byteOffset": 7747, + "byteOffset": 4912, "startColumn": 1, - "startLine": 111 + "startLine": 268 } } } @@ -2412,7 +2412,7 @@ }, "partialFingerprints": { "pareditFindingId": "equality-arity/34d47bdb8164b7a4/0", - "primaryLocationLineHash": "fnv1a64:e3d8d5b8b9adad9b:0" + "primaryLocationLineHash": "fnv1a64:ccef3b6d92b0813b:0" }, "ruleId": "equality-arity" }, @@ -2426,9 +2426,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 7816, + "byteOffset": 4937, "startColumn": 1, - "startLine": 112 + "startLine": 270 } } } @@ -2438,7 +2438,7 @@ }, "partialFingerprints": { "pareditFindingId": "accessor-arity/b4355bf4eacf6bc5/0", - "primaryLocationLineHash": "fnv1a64:9b5275f448c882d6:0" + "primaryLocationLineHash": "fnv1a64:6dd5aa690d24bb46:0" }, "ruleId": "accessor-arity" }, @@ -2454,7 +2454,7 @@ { "deletedRegion": { "byteLength": 21, - "byteOffset": 1359 + "byteOffset": 986 }, "insertedContent": { "text": "(cons al ar)" @@ -2477,9 +2477,9 @@ }, "region": { "byteLength": 21, - "byteOffset": 1359, + "byteOffset": 986, "startColumn": 1, - "startLine": 21 + "startLine": 51 } } } @@ -2489,7 +2489,7 @@ }, "partialFingerprints": { "pareditFindingId": "append-list-to-cons/88d7b250cdb0e3fd/0", - "primaryLocationLineHash": "fnv1a64:53ed80f9b75512ce:0" + "primaryLocationLineHash": "fnv1a64:00f91d5f14f0e56e:0" }, "ruleId": "append-list-to-cons" }, @@ -2505,7 +2505,7 @@ { "deletedRegion": { "byteLength": 20, - "byteOffset": 1433 + "byteOffset": 1031 }, "insertedContent": { "text": "(princ-to-string fs)" @@ -2528,9 +2528,9 @@ }, "region": { "byteLength": 20, - "byteOffset": 1433, + "byteOffset": 1031, "startColumn": 1, - "startLine": 22 + "startLine": 53 } } } @@ -2540,7 +2540,7 @@ }, "partialFingerprints": { "pareditFindingId": "format-to-string/39b50b82e8ac11f4/0", - "primaryLocationLineHash": "fnv1a64:fbf825c42917e7fd:0" + "primaryLocationLineHash": "fnv1a64:bb2ecb9fb2808c33:0" }, "ruleId": "format-to-string" }, @@ -2556,7 +2556,7 @@ { "deletedRegion": { "byteLength": 15, - "byteOffset": 1504 + "byteOffset": 1072 }, "insertedContent": { "text": "(terpri)" @@ -2579,9 +2579,9 @@ }, "region": { "byteLength": 15, - "byteOffset": 1504, + "byteOffset": 1072, "startColumn": 1, - "startLine": 23 + "startLine": 55 } } } @@ -2591,7 +2591,7 @@ }, "partialFingerprints": { "pareditFindingId": "format-newline/b36342f1429c38ae/0", - "primaryLocationLineHash": "fnv1a64:713a8c2ea7d48dd1:0" + "primaryLocationLineHash": "fnv1a64:c282651d9a6f84d1:0" }, "ruleId": "format-newline" }, @@ -2607,7 +2607,7 @@ { "deletedRegion": { "byteLength": 12, - "byteOffset": 1573 + "byteOffset": 1106 }, "insertedContent": { "text": "(floor fq)" @@ -2630,9 +2630,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 1573, + "byteOffset": 1106, "startColumn": 1, - "startLine": 24 + "startLine": 57 } } } @@ -2642,7 +2642,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-divisor/ec0523314eb5cfd2/0", - "primaryLocationLineHash": "fnv1a64:2661273716ad8a49:0" + "primaryLocationLineHash": "fnv1a64:c061d3d69963413d:0" }, "ruleId": "redundant-divisor" }, @@ -2655,10 +2655,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 29, - "byteOffset": 7885, + "byteLength": 35, + "byteOffset": 4969, "startColumn": 1, - "startLine": 113 + "startLine": 272 } } } @@ -2668,7 +2668,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-case-keys/33bca4c760e6356b/0", - "primaryLocationLineHash": "fnv1a64:cdbd75258d01d9bc:0" + "primaryLocationLineHash": "fnv1a64:668e8b9c14f902da:0" }, "ruleId": "duplicate-case-keys" }, @@ -2682,9 +2682,9 @@ }, "region": { "byteLength": 6, - "byteOffset": 7970, - "startColumn": 12, - "startLine": 114 + "byteOffset": 5041, + "startColumn": 4, + "startLine": 278 } } } @@ -2694,7 +2694,7 @@ }, "partialFingerprints": { "pareditFindingId": "quoted-case-key/9a7165a51a9415a2/0", - "primaryLocationLineHash": "fnv1a64:735ee2f495dae0ec:0" + "primaryLocationLineHash": "fnv1a64:6a4f7e926420c564:0" }, "ruleId": "quoted-case-key" }, @@ -2708,9 +2708,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 7986, - "startColumn": 28, - "startLine": 114 + "byteOffset": 5059, + "startColumn": 4, + "startLine": 279 } } } @@ -2720,7 +2720,7 @@ }, "partialFingerprints": { "pareditFindingId": "quoted-case-key/a3c77c1112303135/0", - "primaryLocationLineHash": "fnv1a64:735ee2f495dae0ec:1" + "primaryLocationLineHash": "fnv1a64:dde49a8ede5a560d:0" }, "ruleId": "quoted-case-key" }, @@ -2734,9 +2734,9 @@ }, "region": { "byteLength": 3, - "byteOffset": 8038, - "startColumn": 10, - "startLine": 115 + "byteOffset": 5113, + "startColumn": 4, + "startLine": 283 } } } @@ -2746,7 +2746,7 @@ }, "partialFingerprints": { "pareditFindingId": "case-nil-key/2146ba19257dc6ac/0", - "primaryLocationLineHash": "fnv1a64:625a86911508d9ef:0" + "primaryLocationLineHash": "fnv1a64:7e13aa199b7014c4:0" }, "ruleId": "case-nil-key" }, @@ -2760,9 +2760,9 @@ }, "region": { "byteLength": 3, - "byteOffset": 8109, - "startColumn": 14, - "startLine": 116 + "byteOffset": 5160, + "startColumn": 4, + "startLine": 287 } } } @@ -2772,7 +2772,7 @@ }, "partialFingerprints": { "pareditFindingId": "typecase-nil-key/2146ba19257dc6ac/0", - "primaryLocationLineHash": "fnv1a64:2ba4b132de485ff7:0" + "primaryLocationLineHash": "fnv1a64:aea918da42d03abc:0" }, "ruleId": "typecase-nil-key" }, @@ -2786,9 +2786,9 @@ }, "region": { "byteLength": 1, - "byteOffset": 8184, - "startColumn": 18, - "startLine": 117 + "byteOffset": 5217, + "startColumn": 3, + "startLine": 292 } } } @@ -2798,7 +2798,7 @@ }, "partialFingerprints": { "pareditFindingId": "malformed-case-clause/af63af4c8601a015/0", - "primaryLocationLineHash": "fnv1a64:c74db1edae0d4401:0" + "primaryLocationLineHash": "fnv1a64:92192e2282028a6d:0" }, "ruleId": "malformed-case-clause" }, @@ -2812,9 +2812,9 @@ }, "region": { "byteLength": 4, - "byteOffset": 8186, - "startColumn": 20, - "startLine": 117 + "byteOffset": 5221, + "startColumn": 3, + "startLine": 293 } } } @@ -2824,7 +2824,7 @@ }, "partialFingerprints": { "pareditFindingId": "malformed-case-clause/0aa07f4e709cc5f1/0", - "primaryLocationLineHash": "fnv1a64:c74db1edae0d4401:1" + "primaryLocationLineHash": "fnv1a64:c79b3356673b7703:0" }, "ruleId": "malformed-case-clause" }, @@ -2838,9 +2838,9 @@ }, "region": { "byteLength": 8, - "byteOffset": 8269, - "startColumn": 27, - "startLine": 118 + "byteOffset": 5284, + "startColumn": 3, + "startLine": 298 } } } @@ -2850,7 +2850,7 @@ }, "partialFingerprints": { "pareditFindingId": "unreachable-case-clause/f0fe18a1d1f7cd70/0", - "primaryLocationLineHash": "fnv1a64:89f109d154de306e:0" + "primaryLocationLineHash": "fnv1a64:6761430a43f3bd64:0" }, "ruleId": "unreachable-case-clause" }, @@ -2864,9 +2864,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 8339, - "startColumn": 19, - "startLine": 119 + "byteOffset": 5343, + "startColumn": 3, + "startLine": 302 } } } @@ -2876,7 +2876,7 @@ }, "partialFingerprints": { "pareditFindingId": "exhaustive-case-otherwise/2a99d8e2b6f9f1f7/0", - "primaryLocationLineHash": "fnv1a64:5b1f0f613812b9ba:0" + "primaryLocationLineHash": "fnv1a64:c038dcec4c48c8c9:0" }, "ruleId": "exhaustive-case-otherwise" }, @@ -2889,10 +2889,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 36, - "byteOffset": 8401, + "byteLength": 42, + "byteOffset": 5386, "startColumn": 1, - "startLine": 120 + "startLine": 304 } } } @@ -2902,7 +2902,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-cond-tests/8e590007a2341d0f/0", - "primaryLocationLineHash": "fnv1a64:7fb2d6dd773522fc:0" + "primaryLocationLineHash": "fnv1a64:cb37e0acf30059d7:0" }, "ruleId": "duplicate-cond-tests" }, @@ -2916,9 +2916,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 8498, - "startColumn": 23, - "startLine": 121 + "byteOffset": 5481, + "startColumn": 3, + "startLine": 312 } } } @@ -2928,7 +2928,7 @@ }, "partialFingerprints": { "pareditFindingId": "unreachable-cond-clause/bf880ff3fe6aad2b/0", - "primaryLocationLineHash": "fnv1a64:095ab24fccb44c97:0" + "primaryLocationLineHash": "fnv1a64:97cb167fc7dc8b23:0" }, "ruleId": "unreachable-cond-clause" }, @@ -2942,9 +2942,9 @@ }, "region": { "byteLength": 5, - "byteOffset": 8595, - "startColumn": 42, - "startLine": 122 + "byteOffset": 5566, + "startColumn": 3, + "startLine": 317 } } } @@ -2954,7 +2954,7 @@ }, "partialFingerprints": { "pareditFindingId": "malformed-cond-clause/985b7e37a585f76b/0", - "primaryLocationLineHash": "fnv1a64:4b6a6a40720d6b1f:0" + "primaryLocationLineHash": "fnv1a64:eb11858493ecb631:0" }, "ruleId": "malformed-cond-clause" }, @@ -2967,10 +2967,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 27, - "byteOffset": 8630, + "byteLength": 41, + "byteOffset": 5598, "startColumn": 1, - "startLine": 123 + "startLine": 319 } } } @@ -2980,7 +2980,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-let-bindings/786fd22df524c3b4/0", - "primaryLocationLineHash": "fnv1a64:94391242987acbff:0" + "primaryLocationLineHash": "fnv1a64:6cdc131520de94f4:0" }, "ruleId": "duplicate-let-bindings" }, @@ -2994,9 +2994,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 8713, + "byteOffset": 5672, "startColumn": 7, - "startLine": 124 + "startLine": 324 } } } @@ -3006,7 +3006,7 @@ }, "partialFingerprints": { "pareditFindingId": "malformed-let-binding/b287ea0350e932c2/0", - "primaryLocationLineHash": "fnv1a64:37f482e9c52613ff:0" + "primaryLocationLineHash": "fnv1a64:fc3d54de8f282ba5:0" }, "ruleId": "malformed-let-binding" }, @@ -3020,9 +3020,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 8789, + "byteOffset": 5725, "startColumn": 7, - "startLine": 125 + "startLine": 327 } } } @@ -3032,7 +3032,7 @@ }, "partialFingerprints": { "pareditFindingId": "binds-constant/238892383a531bb8/0", - "primaryLocationLineHash": "fnv1a64:a27a129aebba6333:0" + "primaryLocationLineHash": "fnv1a64:fc3656efe9b7a634:0" }, "ruleId": "binds-constant" }, @@ -3046,9 +3046,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 8797, - "startColumn": 15, - "startLine": 125 + "byteOffset": 5739, + "startColumn": 7, + "startLine": 328 } } } @@ -3058,7 +3058,7 @@ }, "partialFingerprints": { "pareditFindingId": "binds-constant/e7aba77a1dc6c0e4/0", - "primaryLocationLineHash": "fnv1a64:a27a129aebba6333:1" + "primaryLocationLineHash": "fnv1a64:e3cfd23a357a23ea:0" }, "ruleId": "binds-constant" }, @@ -3072,9 +3072,9 @@ }, "region": { "byteLength": 3, - "byteOffset": 8860, + "byteOffset": 5791, "startColumn": 9, - "startLine": 126 + "startLine": 331 } } } @@ -3084,7 +3084,7 @@ }, "partialFingerprints": { "pareditFindingId": "malformed-iteration-spec/0a94b117f74d8cdc/0", - "primaryLocationLineHash": "fnv1a64:442f3db54e8bfb9f:0" + "primaryLocationLineHash": "fnv1a64:8e3f345e01c54dfc:0" }, "ruleId": "malformed-iteration-spec" }, @@ -3098,9 +3098,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 8961, + "byteOffset": 5866, "startColumn": 31, - "startLine": 127 + "startLine": 334 } } } @@ -3110,7 +3110,7 @@ }, "partialFingerprints": { "pareditFindingId": "eval-when-situation/db9d83b2f50bfeff/0", - "primaryLocationLineHash": "fnv1a64:562f7d8ce4c3d05d:0" + "primaryLocationLineHash": "fnv1a64:987fd76f98caa8c6:0" }, "ruleId": "eval-when-situation" }, @@ -3124,9 +3124,9 @@ }, "region": { "byteLength": 10, - "byteOffset": 9005, + "byteOffset": 5905, "startColumn": 1, - "startLine": 128 + "startLine": 337 } } } @@ -3136,7 +3136,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-boolean-operands/20e6cca62d6c6b08/0", - "primaryLocationLineHash": "fnv1a64:340340cbca40b2f9:0" + "primaryLocationLineHash": "fnv1a64:a97f610da4ea75e7:0" }, "ruleId": "duplicate-boolean-operands" }, @@ -3150,9 +3150,9 @@ }, "region": { "byteLength": 32, - "byteOffset": 9086, + "byteOffset": 5946, "startColumn": 1, - "startLine": 129 + "startLine": 339 } } } @@ -3162,7 +3162,7 @@ }, "partialFingerprints": { "pareditFindingId": "dead-boolean-operand/3a7c0733832bd30e/0", - "primaryLocationLineHash": "fnv1a64:92c8ba1375180d7f:0" + "primaryLocationLineHash": "fnv1a64:f9607c38c23610cd:0" }, "ruleId": "dead-boolean-operand" }, @@ -3178,7 +3178,7 @@ { "deletedRegion": { "byteLength": 11, - "byteOffset": 6373 + "byteOffset": 3985 }, "insertedContent": { "text": "(and p q)" @@ -3201,9 +3201,9 @@ }, "region": { "byteLength": 11, - "byteOffset": 6373, + "byteOffset": 3985, "startColumn": 1, - "startLine": 91 + "startLine": 218 } } } @@ -3213,7 +3213,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-boolean-identity/6099f3c432a128b2/0", - "primaryLocationLineHash": "fnv1a64:ba84fff9de9cc9b7:0" + "primaryLocationLineHash": "fnv1a64:3f236e822980ecd7:0" }, "ruleId": "redundant-boolean-identity" }, @@ -3229,7 +3229,7 @@ { "deletedRegion": { "byteLength": 21, - "byteOffset": 6454 + "byteOffset": 4027 }, "insertedContent": { "text": "(not (or p q))" @@ -3252,9 +3252,9 @@ }, "region": { "byteLength": 21, - "byteOffset": 6454, + "byteOffset": 4027, "startColumn": 1, - "startLine": 92 + "startLine": 220 } } } @@ -3264,7 +3264,7 @@ }, "partialFingerprints": { "pareditFindingId": "de-morgan/59f199d4d6ca0ffc/0", - "primaryLocationLineHash": "fnv1a64:addce880015da6a3:0" + "primaryLocationLineHash": "fnv1a64:bd6236437c850ca3:0" }, "ruleId": "de-morgan" }, @@ -3280,7 +3280,7 @@ { "deletedRegion": { "byteLength": 7, - "byteOffset": 3269 + "byteOffset": 2102 }, "insertedContent": { "text": "x" @@ -3303,9 +3303,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 3269, + "byteOffset": 2102, "startColumn": 1, - "startLine": 48 + "startLine": 117 } } } @@ -3315,7 +3315,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-operand-boolean/7e86df9999f069f3/0", - "primaryLocationLineHash": "fnv1a64:7aee93deb4ed2fbc:0" + "primaryLocationLineHash": "fnv1a64:731aa166bc1cfd5c:0" }, "ruleId": "single-operand-boolean" }, @@ -3331,7 +3331,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 3346 + "byteOffset": 2136 }, "insertedContent": { "text": "solo" @@ -3354,9 +3354,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 3346, + "byteOffset": 2136, "startColumn": 1, - "startLine": 49 + "startLine": 119 } } } @@ -3366,7 +3366,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-operand-list-op/6e6fdee3fc4c76f1/0", - "primaryLocationLineHash": "fnv1a64:6940eb67f0869072:0" + "primaryLocationLineHash": "fnv1a64:790ec3f692c67672:0" }, "ruleId": "single-operand-list-op" }, @@ -3382,7 +3382,7 @@ { "deletedRegion": { "byteLength": 5, - "byteOffset": 3423 + "byteOffset": 2176 }, "insertedContent": { "text": "x" @@ -3405,9 +3405,9 @@ }, "region": { "byteLength": 5, - "byteOffset": 3423, + "byteOffset": 2176, "startColumn": 1, - "startLine": 50 + "startLine": 121 } } } @@ -3417,7 +3417,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-operand-arithmetic/5d68a41993e476ea/0", - "primaryLocationLineHash": "fnv1a64:2cf0b47fbeb70e05:0" + "primaryLocationLineHash": "fnv1a64:f775e609b734f11d:0" }, "ruleId": "single-operand-arithmetic" }, @@ -3431,9 +3431,9 @@ }, "region": { "byteLength": 17, - "byteOffset": 9167, + "byteOffset": 6009, "startColumn": 7, - "startLine": 130 + "startLine": 341 } } } @@ -3443,7 +3443,7 @@ }, "partialFingerprints": { "pareditFindingId": "eql-string-comparison/5df8497b5e9f67a1/0", - "primaryLocationLineHash": "fnv1a64:a308a685768efd84:0" + "primaryLocationLineHash": "fnv1a64:05436109130fc575:0" }, "ruleId": "eql-string-comparison" }, @@ -3457,9 +3457,9 @@ }, "region": { "byteLength": 16, - "byteOffset": 9243, + "byteOffset": 6063, "startColumn": 7, - "startLine": 131 + "startLine": 344 } } } @@ -3469,7 +3469,7 @@ }, "partialFingerprints": { "pareditFindingId": "eql-list-comparison/610ef7b2729acd17/0", - "primaryLocationLineHash": "fnv1a64:1efb9e1ea88c80a4:0" + "primaryLocationLineHash": "fnv1a64:f4074d552b1f6b3e:0" }, "ruleId": "eql-list-comparison" }, @@ -3483,9 +3483,9 @@ }, "region": { "byteLength": 18, - "byteOffset": 9336, - "startColumn": 26, - "startLine": 132 + "byteOffset": 6135, + "startColumn": 3, + "startLine": 348 } } } @@ -3495,7 +3495,7 @@ }, "partialFingerprints": { "pareditFindingId": "eql-search-literal/96249e1f05669ad0/0", - "primaryLocationLineHash": "fnv1a64:73b714f4835d1969:0" + "primaryLocationLineHash": "fnv1a64:c48ce83857005e28:0" }, "ruleId": "eql-search-literal" }, @@ -3511,7 +3511,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 6588 + "byteOffset": 4095 }, "insertedContent": { "text": "eql" @@ -3534,9 +3534,9 @@ }, "region": { "byteLength": 8, - "byteOffset": 6587, + "byteOffset": 4094, "startColumn": 1, - "startLine": 94 + "startLine": 224 } } } @@ -3546,7 +3546,7 @@ }, "partialFingerprints": { "pareditFindingId": "eq-number-comparison/23196700b33d9c59/0", - "primaryLocationLineHash": "fnv1a64:8823fcf13b2a50ae:0" + "primaryLocationLineHash": "fnv1a64:3b187ee08e5ca33c:0" }, "ruleId": "eq-number-comparison" }, @@ -3562,7 +3562,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 6663 + "byteOffset": 4128 }, "insertedContent": { "text": "eql" @@ -3585,9 +3585,9 @@ }, "region": { "byteLength": 10, - "byteOffset": 6662, + "byteOffset": 4127, "startColumn": 1, - "startLine": 95 + "startLine": 226 } } } @@ -3597,7 +3597,7 @@ }, "partialFingerprints": { "pareditFindingId": "eq-char-comparison/0372a7cb6b4144bd/0", - "primaryLocationLineHash": "fnv1a64:bcb9cd0e7e2bbd20:0" + "primaryLocationLineHash": "fnv1a64:ad953fe5b53dae54:0" }, "ruleId": "eq-char-comparison" }, @@ -3611,9 +3611,9 @@ }, "region": { "byteLength": 5, - "byteOffset": 9411, - "startColumn": 28, - "startLine": 133 + "byteOffset": 6206, + "startColumn": 9, + "startLine": 351 } } } @@ -3623,7 +3623,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-arg-comparison/4900cb84bed5a9b8/0", - "primaryLocationLineHash": "fnv1a64:c3ddef745e9765df:0" + "primaryLocationLineHash": "fnv1a64:11ded5b75adee42b:0" }, "ruleId": "single-arg-comparison" }, @@ -3639,7 +3639,7 @@ { "deletedRegion": { "byteLength": 11, - "byteOffset": 5529 + "byteOffset": 3516 }, "insertedContent": { "text": "(zerop tally)" @@ -3662,9 +3662,9 @@ }, "region": { "byteLength": 11, - "byteOffset": 5529, + "byteOffset": 3516, "startColumn": 1, - "startLine": 79 + "startLine": 181 } } } @@ -3674,7 +3674,7 @@ }, "partialFingerprints": { "pareditFindingId": "sign-comparison/93d63434e0602a33/0", - "primaryLocationLineHash": "fnv1a64:8a489ffbedab5bfc:0" + "primaryLocationLineHash": "fnv1a64:a85faf57bc42107c:0" }, "ruleId": "sign-comparison" }, @@ -3689,8 +3689,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 17, - "byteOffset": 2632 + "byteLength": 19, + "byteOffset": 1696 }, "insertedContent": { "text": "(when ok (run))" @@ -3712,10 +3712,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 17, - "byteOffset": 2632, + "byteLength": 19, + "byteOffset": 1696, "startColumn": 1, - "startLine": 39 + "startLine": 89 } } } @@ -3725,7 +3725,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-clause-cond/370e08e4584356c3/0", - "primaryLocationLineHash": "fnv1a64:c02a36a77d2ebab0:0" + "primaryLocationLineHash": "fnv1a64:2bcb371ff5e0f782:0" }, "ruleId": "single-clause-cond" }, @@ -3740,11 +3740,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 20, - "byteOffset": 2705 + "byteLength": 30, + "byteOffset": 1738 }, "insertedContent": { - "text": "(progn (r1) (r2))" + "text": "(progn (r1)\n (r2))" } } ] @@ -3763,10 +3763,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 20, - "byteOffset": 2705, + "byteLength": 30, + "byteOffset": 1738, "startColumn": 1, - "startLine": 40 + "startLine": 92 } } } @@ -3776,7 +3776,7 @@ }, "partialFingerprints": { "pareditFindingId": "cond-t-clause/8c478783d564aef8/0", - "primaryLocationLineHash": "fnv1a64:469ce8171b1648e7:0" + "primaryLocationLineHash": "fnv1a64:c3aa67ca700cf43c:0" }, "ruleId": "cond-t-clause" }, @@ -3791,8 +3791,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 36, - "byteOffset": 2994 + "byteLength": 38, + "byteOffset": 1907 }, "insertedContent": { "text": "(let ((mv (vals))) mv)" @@ -3814,10 +3814,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 36, - "byteOffset": 2994, + "byteLength": 38, + "byteOffset": 1907, "startColumn": 1, - "startLine": 44 + "startLine": 104 } } } @@ -3827,7 +3827,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-value-bind/aabdcc153cb0635a/0", - "primaryLocationLineHash": "fnv1a64:d6d9827754af63c1:0" + "primaryLocationLineHash": "fnv1a64:8ec3193454fd444e:0" }, "ruleId": "single-value-bind" }, @@ -3841,9 +3841,9 @@ }, "region": { "byteLength": 17, - "byteOffset": 9483, - "startColumn": 24, - "startLine": 134 + "byteOffset": 6273, + "startColumn": 3, + "startLine": 355 } } } @@ -3853,7 +3853,7 @@ }, "partialFingerprints": { "pareditFindingId": "format-missing-destination/7a85f56d04f4c6ff/0", - "primaryLocationLineHash": "fnv1a64:cbc9f52267cc0c42:0" + "primaryLocationLineHash": "fnv1a64:5a616ec4d0a80801:0" }, "ruleId": "format-missing-destination" }, @@ -3867,9 +3867,9 @@ }, "region": { "byteLength": 8, - "byteOffset": 9560, - "startColumn": 20, - "startLine": 135 + "byteOffset": 6343, + "startColumn": 3, + "startLine": 358 } } } @@ -3879,7 +3879,7 @@ }, "partialFingerprints": { "pareditFindingId": "literal-place/7088193b550b4211/0", - "primaryLocationLineHash": "fnv1a64:dcce8158e138dad0:0" + "primaryLocationLineHash": "fnv1a64:a540c159931cb47b:0" }, "ruleId": "literal-place" }, @@ -3893,9 +3893,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 9628, - "startColumn": 20, - "startLine": 136 + "byteOffset": 6391, + "startColumn": 3, + "startLine": 361 } } } @@ -3905,7 +3905,7 @@ }, "partialFingerprints": { "pareditFindingId": "destructive-literal/5bf9f65d8c2b2acc/0", - "primaryLocationLineHash": "fnv1a64:d8f646b5f21549b2:0" + "primaryLocationLineHash": "fnv1a64:776ad11e843bf038:0" }, "ruleId": "destructive-literal" }, @@ -3919,9 +3919,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 9711, - "startColumn": 28, - "startLine": 137 + "byteOffset": 6464, + "startColumn": 9, + "startLine": 364 } } } @@ -3931,7 +3931,7 @@ }, "partialFingerprints": { "pareditFindingId": "char-op-string/90d896193ca587cd/0", - "primaryLocationLineHash": "fnv1a64:df72af9466c90c29:0" + "primaryLocationLineHash": "fnv1a64:f4331714955a3bc3:0" }, "ruleId": "char-op-string" }, @@ -3945,9 +3945,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 9778, - "startColumn": 26, - "startLine": 138 + "byteOffset": 6534, + "startColumn": 3, + "startLine": 368 } } } @@ -3957,7 +3957,7 @@ }, "partialFingerprints": { "pareditFindingId": "empty-body/713b5add40eb9a23/0", - "primaryLocationLineHash": "fnv1a64:13d43d7f3e8e34d8:0" + "primaryLocationLineHash": "fnv1a64:c7a60d2211f5d9e9:0" }, "ruleId": "empty-body" }, @@ -3971,9 +3971,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 9840, - "startColumn": 23, - "startLine": 139 + "byteOffset": 6586, + "startColumn": 3, + "startLine": 371 } } } @@ -3983,7 +3983,7 @@ }, "partialFingerprints": { "pareditFindingId": "identity-arithmetic/5957946d13e87c0f/0", - "primaryLocationLineHash": "fnv1a64:e3f2c3976f0803ae:0" + "primaryLocationLineHash": "fnv1a64:c18489e666a8a30f:0" }, "ruleId": "identity-arithmetic" }, @@ -3999,7 +3999,7 @@ { "deletedRegion": { "byteLength": 9, - "byteOffset": 1645 + "byteOffset": 1140 }, "insertedContent": { "text": "(- amt)" @@ -4022,9 +4022,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 1645, + "byteOffset": 1140, "startColumn": 1, - "startLine": 25 + "startLine": 59 } } } @@ -4034,7 +4034,7 @@ }, "partialFingerprints": { "pareditFindingId": "verbose-negation/db07057c02c96d6b/0", - "primaryLocationLineHash": "fnv1a64:05f507d4301cf8e6:0" + "primaryLocationLineHash": "fnv1a64:ecc15495cd705b7e:0" }, "ruleId": "verbose-negation" }, @@ -4050,7 +4050,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 1716 + "byteOffset": 1170 }, "insertedContent": { "text": "(cons la lb)" @@ -4073,9 +4073,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 1716, + "byteOffset": 1170, "startColumn": 1, - "startLine": 26 + "startLine": 61 } } } @@ -4085,7 +4085,7 @@ }, "partialFingerprints": { "pareditFindingId": "list-star-to-cons/8dfbceb8e6484013/0", - "primaryLocationLineHash": "fnv1a64:841c939526f306b8:0" + "primaryLocationLineHash": "fnv1a64:ca6d7c7781530d28:0" }, "ruleId": "list-star-to-cons" }, @@ -4101,7 +4101,7 @@ { "deletedRegion": { "byteLength": 26, - "byteOffset": 1788 + "byteOffset": 1205 }, "insertedContent": { "text": "(values va vb)" @@ -4124,9 +4124,9 @@ }, "region": { "byteLength": 26, - "byteOffset": 1788, + "byteOffset": 1205, "startColumn": 1, - "startLine": 27 + "startLine": 63 } } } @@ -4136,7 +4136,7 @@ }, "partialFingerprints": { "pareditFindingId": "values-list-of-list/a01fe3b901d6d599/0", - "primaryLocationLineHash": "fnv1a64:ae17b6d2459fc324:0" + "primaryLocationLineHash": "fnv1a64:173232562b0259aa:0" }, "ruleId": "values-list-of-list" }, @@ -4151,8 +4151,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 13, - "byteOffset": 1862 + "byteLength": 15, + "byteOffset": 1255 }, "insertedContent": { "text": "(p1x)" @@ -4174,10 +4174,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 13, - "byteOffset": 1862, + "byteLength": 15, + "byteOffset": 1255, "startColumn": 1, - "startLine": 28 + "startLine": 65 } } } @@ -4187,7 +4187,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-prog1/d11c68d1c2a8c075/0", - "primaryLocationLineHash": "fnv1a64:b8f40ca236cb4c3a:0" + "primaryLocationLineHash": "fnv1a64:567951eb6e91065d:0" }, "ruleId": "redundant-prog1" }, @@ -4203,7 +4203,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 1932 + "byteOffset": 1290 }, "insertedContent": { "text": "(copy-seq sz)" @@ -4226,9 +4226,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 1932, + "byteOffset": 1290, "startColumn": 1, - "startLine": 29 + "startLine": 68 } } } @@ -4238,7 +4238,7 @@ }, "partialFingerprints": { "pareditFindingId": "subseq-zero/86623ddc853cc31a/0", - "primaryLocationLineHash": "fnv1a64:26d5740759625745:0" + "primaryLocationLineHash": "fnv1a64:a17e295ebedaa8f5:0" }, "ruleId": "subseq-zero" }, @@ -4254,7 +4254,7 @@ { "deletedRegion": { "byteLength": 20, - "byteOffset": 1998 + "byteOffset": 1319 }, "insertedContent": { "text": "(nth cn cx)" @@ -4277,9 +4277,9 @@ }, "region": { "byteLength": 20, - "byteOffset": 1998, + "byteOffset": 1319, "startColumn": 1, - "startLine": 30 + "startLine": 70 } } } @@ -4289,7 +4289,7 @@ }, "partialFingerprints": { "pareditFindingId": "car-nthcdr/fa5f8068ce51888c/0", - "primaryLocationLineHash": "fnv1a64:ebc22df4f9d155d3:0" + "primaryLocationLineHash": "fnv1a64:174875f8fcb7f4db:0" }, "ruleId": "car-nthcdr" }, @@ -4305,7 +4305,7 @@ { "deletedRegion": { "byteLength": 19, - "byteOffset": 2063 + "byteOffset": 1354 }, "insertedContent": { "text": "(car (last crx))" @@ -4328,9 +4328,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 2063, + "byteOffset": 1354, "startColumn": 1, - "startLine": 31 + "startLine": 72 } } } @@ -4340,7 +4340,7 @@ }, "partialFingerprints": { "pareditFindingId": "car-reverse/358664c82b8eb6c2/0", - "primaryLocationLineHash": "fnv1a64:50347c7603a050b5:0" + "primaryLocationLineHash": "fnv1a64:74b2319d6206c235:0" }, "ruleId": "car-reverse" }, @@ -4356,7 +4356,7 @@ { "deletedRegion": { "byteLength": 16, - "byteOffset": 2129 + "byteOffset": 1389 }, "insertedContent": { "text": "(copy-list anx)" @@ -4379,9 +4379,9 @@ }, "region": { "byteLength": 16, - "byteOffset": 2129, + "byteOffset": 1389, "startColumn": 1, - "startLine": 32 + "startLine": 74 } } } @@ -4391,7 +4391,7 @@ }, "partialFingerprints": { "pareditFindingId": "append-nil/9dcde276136a9a2c/0", - "primaryLocationLineHash": "fnv1a64:655fffeff878b55b:0" + "primaryLocationLineHash": "fnv1a64:497b7f35513a63d7:0" }, "ruleId": "append-nil" }, @@ -4407,7 +4407,7 @@ { "deletedRegion": { "byteLength": 38, - "byteOffset": 2194 + "byteOffset": 1420 }, "insertedContent": { "text": "(list mva mvb)" @@ -4430,9 +4430,9 @@ }, "region": { "byteLength": 38, - "byteOffset": 2194, + "byteOffset": 1420, "startColumn": 1, - "startLine": 33 + "startLine": 76 } } } @@ -4442,7 +4442,7 @@ }, "partialFingerprints": { "pareditFindingId": "multiple-value-list-of-values/1b4099bfb77b9dcf/0", - "primaryLocationLineHash": "fnv1a64:ff426032c066c22a:0" + "primaryLocationLineHash": "fnv1a64:f1fe2aedbd31e474:0" }, "ruleId": "multiple-value-list-of-values" }, @@ -4458,7 +4458,7 @@ { "deletedRegion": { "byteLength": 19, - "byteOffset": 2278 + "byteOffset": 1492 }, "insertedContent": { "text": "(stringp tpx)" @@ -4481,9 +4481,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 2278, + "byteOffset": 1492, "startColumn": 1, - "startLine": 34 + "startLine": 78 } } } @@ -4493,7 +4493,7 @@ }, "partialFingerprints": { "pareditFindingId": "typep-predicate/c4524e22023511e4/0", - "primaryLocationLineHash": "fnv1a64:150074136afea02b:0" + "primaryLocationLineHash": "fnv1a64:aef6e773733f332b:0" }, "ruleId": "typep-predicate" }, @@ -4509,7 +4509,7 @@ { "deletedRegion": { "byteLength": 14, - "byteOffset": 2348 + "byteOffset": 1531 }, "insertedContent": { "text": "ctx" @@ -4532,9 +4532,9 @@ }, "region": { "byteLength": 14, - "byteOffset": 2348, + "byteOffset": 1531, "startColumn": 1, - "startLine": 35 + "startLine": 80 } } } @@ -4544,7 +4544,7 @@ }, "partialFingerprints": { "pareditFindingId": "coerce-to-t/5287c8c7f1849642/0", - "primaryLocationLineHash": "fnv1a64:8cb3d956aa394b6d:0" + "primaryLocationLineHash": "fnv1a64:64c650102f8471a5:0" }, "ruleId": "coerce-to-t" }, @@ -4560,7 +4560,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 2430 + "byteOffset": 1577 }, "insertedContent": { "text": "" @@ -4583,9 +4583,9 @@ }, "region": { "byteLength": 21, - "byteOffset": 2414, + "byteOffset": 1561, "startColumn": 1, - "startLine": 36 + "startLine": 82 } } } @@ -4595,7 +4595,7 @@ }, "partialFingerprints": { "pareditFindingId": "gethash-default/f31c83fc13478b4e/0", - "primaryLocationLineHash": "fnv1a64:0dd73547e000f721:0" + "primaryLocationLineHash": "fnv1a64:085c9292655ef661:0" }, "ruleId": "gethash-default" }, @@ -4611,7 +4611,7 @@ { "deletedRegion": { "byteLength": 11, - "byteOffset": 2500 + "byteOffset": 1618 }, "insertedContent": { "text": "" @@ -4634,9 +4634,9 @@ }, "region": { "byteLength": 28, - "byteOffset": 2484, + "byteOffset": 1602, "startColumn": 1, - "startLine": 37 + "startLine": 84 } } } @@ -4646,7 +4646,7 @@ }, "partialFingerprints": { "pareditFindingId": "make-hash-table-test/35479fa9b5b47097/0", - "primaryLocationLineHash": "fnv1a64:d76a26ccd4ace822:0" + "primaryLocationLineHash": "fnv1a64:49640e8e765c65de:0" }, "ruleId": "make-hash-table-test" }, @@ -4660,9 +4660,9 @@ }, "region": { "byteLength": 7, - "byteOffset": 9892, + "byteOffset": 6618, "startColumn": 1, - "startLine": 140 + "startLine": 373 } } } @@ -4672,7 +4672,7 @@ }, "partialFingerprints": { "pareditFindingId": "zero-divisor/bb4a55b5af90f7db/0", - "primaryLocationLineHash": "fnv1a64:46d32820c2d19b98:0" + "primaryLocationLineHash": "fnv1a64:03708acf77f01e78:0" }, "ruleId": "zero-divisor" }, @@ -4686,9 +4686,9 @@ }, "region": { "byteLength": 28, - "byteOffset": 9959, + "byteOffset": 6642, "startColumn": 1, - "startLine": 141 + "startLine": 375 } } } @@ -4698,7 +4698,7 @@ }, "partialFingerprints": { "pareditFindingId": "duplicate-keyword/9a11e6557d3eae3f/0", - "primaryLocationLineHash": "fnv1a64:0262b9454fa3263e:0" + "primaryLocationLineHash": "fnv1a64:17c90107a4d6fa6e:0" }, "ruleId": "duplicate-keyword" }, @@ -4712,9 +4712,9 @@ }, "region": { "byteLength": 32, - "byteOffset": 10031, + "byteOffset": 6692, "startColumn": 1, - "startLine": 142 + "startLine": 377 } } } @@ -4724,7 +4724,7 @@ }, "partialFingerprints": { "pareditFindingId": "defpackage-quoted/c37b38bb92c1afca/0", - "primaryLocationLineHash": "fnv1a64:cbd05bff89b3ba69:0" + "primaryLocationLineHash": "fnv1a64:c7e99281f90ece69:0" }, "ruleId": "defpackage-quoted" }, @@ -4738,9 +4738,9 @@ }, "region": { "byteLength": 16, - "byteOffset": 10103, + "byteOffset": 6746, "startColumn": 1, - "startLine": 143 + "startLine": 379 } } } @@ -4750,7 +4750,7 @@ }, "partialFingerprints": { "pareditFindingId": "step-zero/d9ce2059b5b3a5cc/0", - "primaryLocationLineHash": "fnv1a64:190005d79758c96f:0" + "primaryLocationLineHash": "fnv1a64:6fe2fecda59c1c3d:0" }, "ruleId": "step-zero" }, @@ -4765,8 +4765,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 17, - "byteOffset": 5861 + "byteLength": 25, + "byteOffset": 3688 }, "insertedContent": { "text": "(unless iu (iue))" @@ -4788,10 +4788,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 17, - "byteOffset": 5861, + "byteLength": 25, + "byteOffset": 3688, "startColumn": 1, - "startLine": 84 + "startLine": 197 } } } @@ -4801,7 +4801,7 @@ }, "partialFingerprints": { "pareditFindingId": "if-to-unless/54bbf94ef24fbf44/0", - "primaryLocationLineHash": "fnv1a64:7fb6301083e69a7b:0" + "primaryLocationLineHash": "fnv1a64:35cac5e6203d708a:0" }, "ruleId": "if-to-unless" }, @@ -4817,7 +4817,7 @@ { "deletedRegion": { "byteLength": 5, - "byteOffset": 5929 + "byteOffset": 3731 }, "insertedContent": { "text": "progn" @@ -4839,10 +4839,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 19, - "byteOffset": 5928, + "byteLength": 23, + "byteOffset": 3730, "startColumn": 1, - "startLine": 85 + "startLine": 201 } } } @@ -4852,7 +4852,7 @@ }, "partialFingerprints": { "pareditFindingId": "prog2-to-progn/cfc0af416a06509b/0", - "primaryLocationLineHash": "fnv1a64:880ff7f77631cbec:0" + "primaryLocationLineHash": "fnv1a64:64ad164304216e7a:0" }, "ruleId": "prog2-to-progn" }, @@ -4868,7 +4868,7 @@ { "deletedRegion": { "byteLength": 20, - "byteOffset": 5997 + "byteOffset": 3772 }, "insertedContent": { "text": "(hcx)" @@ -4891,9 +4891,9 @@ }, "region": { "byteLength": 20, - "byteOffset": 5997, + "byteOffset": 3772, "startColumn": 1, - "startLine": 86 + "startLine": 205 } } } @@ -4903,7 +4903,7 @@ }, "partialFingerprints": { "pareditFindingId": "handler-case-no-clauses/e6eca94ec47a803d/0", - "primaryLocationLineHash": "fnv1a64:cbb9b0bcef091a70:0" + "primaryLocationLineHash": "fnv1a64:4f24f39bb9b967de:0" }, "ruleId": "handler-case-no-clauses" }, @@ -4919,7 +4919,7 @@ { "deletedRegion": { "byteLength": 22, - "byteOffset": 6075 + "byteOffset": 3820 }, "insertedContent": { "text": "(upx)" @@ -4942,9 +4942,9 @@ }, "region": { "byteLength": 22, - "byteOffset": 6075, + "byteOffset": 3820, "startColumn": 1, - "startLine": 87 + "startLine": 207 } } } @@ -4954,7 +4954,7 @@ }, "partialFingerprints": { "pareditFindingId": "unwind-protect-no-cleanup/0517ee52f6bcfa89/0", - "primaryLocationLineHash": "fnv1a64:8ffbee69202c9404:0" + "primaryLocationLineHash": "fnv1a64:3d02561dc1d4ae9a:0" }, "ruleId": "unwind-protect-no-cleanup" }, @@ -4970,7 +4970,7 @@ { "deletedRegion": { "byteLength": 9, - "byteOffset": 4278 + "byteOffset": 2626 }, "insertedContent": { "text": "" @@ -4993,9 +4993,9 @@ }, "region": { "byteLength": 23, - "byteOffset": 4265, + "byteOffset": 2613, "startColumn": 1, - "startLine": 62 + "startLine": 147 } } } @@ -5005,7 +5005,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-start-zero/204c4a0fd8b6054d/0", - "primaryLocationLineHash": "fnv1a64:265ed6e4030ca4a6:0" + "primaryLocationLineHash": "fnv1a64:d667dcc409ab57e6:0" }, "ruleId": "redundant-start-zero" }, @@ -5021,7 +5021,7 @@ { "deletedRegion": { "byteLength": 9, - "byteOffset": 4353 + "byteOffset": 2674 }, "insertedContent": { "text": "" @@ -5044,9 +5044,9 @@ }, "region": { "byteLength": 23, - "byteOffset": 4340, + "byteOffset": 2661, "startColumn": 1, - "startLine": 63 + "startLine": 149 } } } @@ -5056,7 +5056,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-end-nil/95fb7a788caa4221/0", - "primaryLocationLineHash": "fnv1a64:66041a6b31ab3a16:0" + "primaryLocationLineHash": "fnv1a64:4fff6e90488d69d6:0" }, "ruleId": "redundant-end-nil" }, @@ -5072,7 +5072,7 @@ { "deletedRegion": { "byteLength": 14, - "byteOffset": 4425 + "byteOffset": 2719 }, "insertedContent": { "text": "" @@ -5095,9 +5095,9 @@ }, "region": { "byteLength": 28, - "byteOffset": 4412, + "byteOffset": 2706, "startColumn": 1, - "startLine": 64 + "startLine": 151 } } } @@ -5107,7 +5107,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-from-end-nil/74a10cdf08c695fc/0", - "primaryLocationLineHash": "fnv1a64:02f162094382953b:0" + "primaryLocationLineHash": "fnv1a64:f9ab16add3fb37df:0" }, "ruleId": "redundant-from-end-nil" }, @@ -5123,7 +5123,7 @@ { "deletedRegion": { "byteLength": 11, - "byteOffset": 4504 + "byteOffset": 2776 }, "insertedContent": { "text": "" @@ -5146,9 +5146,9 @@ }, "region": { "byteLength": 27, - "byteOffset": 4489, + "byteOffset": 2761, "startColumn": 1, - "startLine": 65 + "startLine": 153 } } } @@ -5158,7 +5158,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-count-nil/b4e4e8611abe92d2/0", - "primaryLocationLineHash": "fnv1a64:67d1a75dcc399bd9:0" + "primaryLocationLineHash": "fnv1a64:4b403d80585f0df9:0" }, "ruleId": "redundant-count-nil" }, @@ -5174,7 +5174,7 @@ { "deletedRegion": { "byteLength": 51, - "byteOffset": 4563 + "byteOffset": 2812 }, "insertedContent": { "text": "(string-equal sa sb)" @@ -5197,9 +5197,9 @@ }, "region": { "byteLength": 51, - "byteOffset": 4563, + "byteOffset": 2812, "startColumn": 1, - "startLine": 66 + "startLine": 155 } } } @@ -5225,7 +5225,7 @@ { "deletedRegion": { "byteLength": 45, - "byteOffset": 4634 + "byteOffset": 2884 }, "insertedContent": { "text": "(char-equal ca cb)" @@ -5248,9 +5248,9 @@ }, "region": { "byteLength": 45, - "byteOffset": 4634, + "byteOffset": 2884, "startColumn": 1, - "startLine": 67 + "startLine": 157 } } } @@ -5260,7 +5260,7 @@ }, "partialFingerprints": { "pareditFindingId": "char-case-fold/1151e7de6ce93524/0", - "primaryLocationLineHash": "fnv1a64:ec5db26fa217dc7d:0" + "primaryLocationLineHash": "fnv1a64:11d487eec5dfecf5:0" }, "ruleId": "char-case-fold" }, @@ -5276,7 +5276,7 @@ { "deletedRegion": { "byteLength": 37, - "byteOffset": 4703 + "byteOffset": 2948 }, "insertedContent": { "text": "(string-upcase nsc)" @@ -5299,9 +5299,9 @@ }, "region": { "byteLength": 37, - "byteOffset": 4703, + "byteOffset": 2948, "startColumn": 1, - "startLine": 68 + "startLine": 159 } } } @@ -5311,7 +5311,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-string-case/e1b50d70e857d80e/0", - "primaryLocationLineHash": "fnv1a64:ef1a410c52dedcd1:0" + "primaryLocationLineHash": "fnv1a64:025542eb348f6ed1:0" }, "ruleId": "nested-string-case" }, @@ -5327,7 +5327,7 @@ { "deletedRegion": { "byteLength": 27, - "byteOffset": 4776 + "byteOffset": 3008 }, "insertedContent": { "text": "ccc" @@ -5350,9 +5350,9 @@ }, "region": { "byteLength": 27, - "byteOffset": 4776, + "byteOffset": 3008, "startColumn": 1, - "startLine": 69 + "startLine": 161 } } } @@ -5362,7 +5362,7 @@ }, "partialFingerprints": { "pareditFindingId": "code-char-char-code/d64bd87a6ec1dd94/0", - "primaryLocationLineHash": "fnv1a64:93c30af215b8c70f:0" + "primaryLocationLineHash": "fnv1a64:6ae60832fbe5a56f:0" }, "ruleId": "code-char-char-code" }, @@ -5378,7 +5378,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 4859 + "byteOffset": 3068 }, "insertedContent": { "text": "" @@ -5401,9 +5401,9 @@ }, "region": { "byteLength": 12, - "byteOffset": 4850, + "byteOffset": 3059, "startColumn": 1, - "startLine": 70 + "startLine": 163 } } } @@ -5413,7 +5413,7 @@ }, "partialFingerprints": { "pareditFindingId": "last-default-count/ee8e9f6b4ebb33ac/0", - "primaryLocationLineHash": "fnv1a64:c4aa05876e209b07:0" + "primaryLocationLineHash": "fnv1a64:acc8598eecbc985b:0" }, "ruleId": "last-default-count" }, @@ -5429,7 +5429,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 4935 + "byteOffset": 3106 }, "insertedContent": { "text": "" @@ -5452,9 +5452,9 @@ }, "region": { "byteLength": 15, - "byteOffset": 4923, + "byteOffset": 3094, "startColumn": 1, - "startLine": 71 + "startLine": 165 } } } @@ -5464,7 +5464,7 @@ }, "partialFingerprints": { "pareditFindingId": "butlast-default-count/6841ef3bad2f901d/0", - "primaryLocationLineHash": "fnv1a64:2de496c2b2f4618e:0" + "primaryLocationLineHash": "fnv1a64:618bd292252980ae:0" }, "ruleId": "butlast-default-count" }, @@ -5480,7 +5480,7 @@ { "deletedRegion": { "byteLength": 21, - "byteOffset": 5013 + "byteOffset": 3149 }, "insertedContent": { "text": "" @@ -5503,9 +5503,9 @@ }, "region": { "byteLength": 36, - "byteOffset": 4999, + "byteOffset": 3135, "startColumn": 1, - "startLine": 72 + "startLine": 167 } } } @@ -5515,7 +5515,7 @@ }, "partialFingerprints": { "pareditFindingId": "make-list-default-element/091b9e3ccae97a5b/0", - "primaryLocationLineHash": "fnv1a64:f134cf1ec5c57582:0" + "primaryLocationLineHash": "fnv1a64:c50175a4a5fa0c24:0" }, "ruleId": "make-list-default-element" }, @@ -5531,7 +5531,7 @@ { "deletedRegion": { "byteLength": 10, - "byteOffset": 5097 + "byteOffset": 3219 }, "insertedContent": { "text": "" @@ -5554,9 +5554,9 @@ }, "region": { "byteLength": 29, - "byteOffset": 5079, + "byteOffset": 3201, "startColumn": 1, - "startLine": 73 + "startLine": 169 } } } @@ -5566,7 +5566,7 @@ }, "partialFingerprints": { "pareditFindingId": "parse-integer-default-radix/6689082ca07df47e/0", - "primaryLocationLineHash": "fnv1a64:3bc6cd984c53e181:0" + "primaryLocationLineHash": "fnv1a64:429f51e6e6fe2349:0" }, "ruleId": "parse-integer-default-radix" }, @@ -5582,7 +5582,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 5175 + "byteOffset": 3276 }, "insertedContent": { "text": "" @@ -5605,9 +5605,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 5161, + "byteOffset": 3262, "startColumn": 1, - "startLine": 74 + "startLine": 171 } } } @@ -5617,7 +5617,7 @@ }, "partialFingerprints": { "pareditFindingId": "getf-default-nil/ccab3d746985ff27/0", - "primaryLocationLineHash": "fnv1a64:9f300e0d98fe75ca:0" + "primaryLocationLineHash": "fnv1a64:519e4bba8d8c6b4a:0" }, "ruleId": "getf-default-nil" }, @@ -5633,7 +5633,7 @@ { "deletedRegion": { "byteLength": 16, - "byteOffset": 5248 + "byteOffset": 3318 }, "insertedContent": { "text": "" @@ -5656,9 +5656,9 @@ }, "region": { "byteLength": 33, - "byteOffset": 5232, + "byteOffset": 3302, "startColumn": 1, - "startLine": 75 + "startLine": 173 } } } @@ -5668,7 +5668,7 @@ }, "partialFingerprints": { "pareditFindingId": "make-array-default-keyword/5378b26260ebe135/0", - "primaryLocationLineHash": "fnv1a64:a2ffafa15fed183c:0" + "primaryLocationLineHash": "fnv1a64:5d1e346df151f1b4:0" }, "ruleId": "make-array-default-keyword" }, @@ -5684,7 +5684,7 @@ { "deletedRegion": { "byteLength": 33, - "byteOffset": 5313 + "byteOffset": 3366 }, "insertedContent": { "text": "(char-upcase ncc)" @@ -5707,9 +5707,9 @@ }, "region": { "byteLength": 33, - "byteOffset": 5313, + "byteOffset": 3366, "startColumn": 1, - "startLine": 76 + "startLine": 175 } } } @@ -5719,7 +5719,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-char-case/e5d63774dec3163c/0", - "primaryLocationLineHash": "fnv1a64:08e80a03a324ed75:0" + "primaryLocationLineHash": "fnv1a64:dac7186c78fce6ed:0" }, "ruleId": "nested-char-case" }, @@ -5735,7 +5735,7 @@ { "deletedRegion": { "byteLength": 5, - "byteOffset": 5385 + "byteOffset": 3421 }, "insertedContent": { "text": "list" @@ -5744,7 +5744,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 5400 + "byteOffset": 3436 }, "insertedContent": { "text": "" @@ -5767,9 +5767,9 @@ }, "region": { "byteLength": 21, - "byteOffset": 5384, + "byteOffset": 3420, "startColumn": 1, - "startLine": 77 + "startLine": 177 } } } @@ -5779,7 +5779,7 @@ }, "partialFingerprints": { "pareditFindingId": "list-star-nil/3d15900073a4c4e4/0", - "primaryLocationLineHash": "fnv1a64:d28afb89e5c98c47:0" + "primaryLocationLineHash": "fnv1a64:45c6a2a2c72bbb5f:0" }, "ruleId": "list-star-nil" }, @@ -5792,7 +5792,7 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 10167, + "byteLength": 6775, "byteOffset": 0, "startColumn": 1, "startLine": 1 @@ -5819,9 +5819,9 @@ }, "region": { "byteLength": 9, - "byteOffset": 8864, - "startColumn": 13, - "startLine": 126 + "byteOffset": 5797, + "startColumn": 3, + "startLine": 332 } } } @@ -5831,7 +5831,7 @@ }, "partialFingerprints": { "pareditFindingId": "leftover-print-debug/8410f5d691961e8d/0", - "primaryLocationLineHash": "fnv1a64:29e9a5a3d9f5c899:0" + "primaryLocationLineHash": "fnv1a64:e20aba3f7adaed85:0" }, "ruleId": "leftover-print-debug" }, @@ -5845,9 +5845,9 @@ }, "region": { "byteLength": 32, - "byteOffset": 10031, + "byteOffset": 6692, "startColumn": 1, - "startLine": 142 + "startLine": 377 } } } @@ -5857,7 +5857,7 @@ }, "partialFingerprints": { "pareditFindingId": "defpackage-without-in-package/c37b38bb92c1afca/0", - "primaryLocationLineHash": "fnv1a64:e0002aef755c8604:0" + "primaryLocationLineHash": "fnv1a64:e21470825880c526:0" }, "ruleId": "defpackage-without-in-package" }, @@ -5870,10 +5870,10 @@ "uri": "broad.lisp" }, "region": { - "byteLength": 21, - "byteOffset": 2920, + "byteLength": 23, + "byteOffset": 1860, "startColumn": 1, - "startLine": 43 + "startLine": 101 } } } @@ -5883,7 +5883,7 @@ }, "partialFingerprints": { "pareditFindingId": "return-from-unmatched-block/83c6c0866319952f/0", - "primaryLocationLineHash": "fnv1a64:0e588b483baf867e:0" + "primaryLocationLineHash": "fnv1a64:760ad44109c6af12:0" }, "ruleId": "return-from-unmatched-block" }, @@ -5897,9 +5897,9 @@ }, "region": { "byteLength": 1, - "byteOffset": 8637, + "byteOffset": 5605, "startColumn": 8, - "startLine": 123 + "startLine": 319 } } } @@ -5909,7 +5909,7 @@ }, "partialFingerprints": { "pareditFindingId": "unused-local-binding/af63f54c86021707/0", - "primaryLocationLineHash": "fnv1a64:657f9c9189fd01e1:0" + "primaryLocationLineHash": "fnv1a64:6a3c8e0ef61da356:0" }, "ruleId": "unused-local-binding" }, @@ -5923,9 +5923,9 @@ }, "region": { "byteLength": 1, - "byteOffset": 8643, - "startColumn": 14, - "startLine": 123 + "byteOffset": 5617, + "startColumn": 8, + "startLine": 320 } } } @@ -5935,7 +5935,7 @@ }, "partialFingerprints": { "pareditFindingId": "unused-local-binding/af63f44c86021554/0", - "primaryLocationLineHash": "fnv1a64:657f9c9189fd01e1:1" + "primaryLocationLineHash": "fnv1a64:d936185404eee2cf:0" }, "ruleId": "unused-local-binding" } diff --git a/tests/fixtures/lint_golden/expected/broad.text.golden b/tests/fixtures/lint_golden/expected/broad.text.golden index f1a81f2e9..6932d8e51 100644 --- a/tests/fixtures/lint_golden/expected/broad.text.golden +++ b/tests/fixtures/lint_golden/expected/broad.text.golden @@ -341,146 +341,146 @@ rule contains-on-non-associative 0 rule reference-type-operator-mismatch 0 rule macro-body-destroys-argument-form 0 rule macrolet-expander-captures-lexical-variable 0 -finding self-assignment error suspicious fixable=false broad.lisp 6875 setq assigns place x to itself self-assignment/5f1a5b802aa99b47/0 -finding duplicate-setf-places error duplicate fixable=false broad.lisp 6961 setf assigns variable total more than once; the earlier assignment is dead duplicate-setf-places/8104810ed815b9fd/0 -finding setf-arity error arity fixable=false broad.lisp 7021 setf has 3 arguments; place/value pairs require an even count setf-arity/b0a5b422aad6d4d2/0 -finding setq-non-variable error malformed fixable=false broad.lisp 7092 setq place (car x) is not a variable setq-non-variable/93a38b0abb06fba2/0 -finding manual-incf warning suspicious fixable=true broad.lisp 3644 setf manually adjusts a variable; use incf manual-incf/e9cc51bb9767dcb7/0 -finding manual-push warning suspicious fixable=true broad.lisp 3710 setf conses onto a variable; use push manual-push/4847791ff6aa61f5/0 -finding manual-pushnew warning suspicious fixable=true broad.lisp 3776 setf adjoins onto a variable; use pushnew manual-pushnew/1e8f91739c283b2f/0 -finding explicit-step-delta warning suspicious fixable=true broad.lisp 2773 incf delta of 1 is the default; (incf x 1) is (incf x) explicit-step-delta/00a1f8d32f2b1a3f/0 -finding negated-step-delta warning suspicious fixable=true broad.lisp 2847 negative delta flips the operator; use decf with a positive delta negated-step-delta/c72d843010c3cb77/0 -finding explicit-nil-return warning suspicious fixable=true broad.lisp 2920 return-from nil result is the default; drop the redundant nil explicit-nil-return/83c6c0866319952f/0 -finding cons-to-list warning suspicious fixable=true broad.lisp 1223 cons onto nil/a list is a list constructor; use list cons-to-list/30734641edf18c29/0 -finding double-reverse warning suspicious fixable=true broad.lisp 1290 (reverse (reverse x)) is a wasteful copy; use (copy-seq x) double-reverse/64abc2d4def62155/0 -finding modify-macro-arity error arity fixable=false broad.lisp 7158 incf takes 1 or 2 argument(s) but has 3 modify-macro-arity/1c9711db871ff5e7/0 -finding duplicate-parameters error duplicate fixable=false broad.lisp 7231 scale names parameter factor more than once (2×) duplicate-parameters/fc20fd38e853fe41/0 -finding duplicate-lambda-list-keyword error duplicate fixable=false broad.lisp 7306 dupkw repeats lambda-list keyword &optional (2×) duplicate-lambda-list-keyword/2f60a48b9e4ef7e3/0 -finding lambda-list-keyword-order error malformed fixable=false broad.lisp 7390 kworder lists lambda-list keyword &optional after &key lambda-list-keyword-order/617c0a49865251a2/0 -finding redundant-quote warning suspicious fixable=true broad.lisp 438 quoting number 5 is redundant redundant-quote/07bb8307b4864109/0 -finding redundant-progn warning suspicious fixable=true broad.lisp 502 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/a2fdba9820c97822/0 -finding nested-progn warning suspicious fixable=true broad.lisp 581 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/5cd55ce143529b1f/0 -finding nested-when warning suspicious fixable=true broad.lisp 3135 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/3709b9f1558a096d/0 -finding nested-unless warning suspicious fixable=true broad.lisp 3201 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/374f1c05f4fd74ef/0 -finding nested-boolean warning suspicious fixable=true broad.lisp 3073 or nested in a or flattens; its operands splice in nested-boolean/62bd4b586d0045bf/0 -finding nested-cxr warning suspicious fixable=true broad.lisp 3845 nested car/cdr accessors combine into (cadr …) nested-cxr/109a80ae72e5eb4e/0 -finding nth-constant-index warning suspicious fixable=true broad.lisp 3910 nth with a constant index; use (first …) nth-constant-index/9c4d78c87d9ad119/0 -finding nthcdr-zero warning suspicious fixable=true broad.lisp 3983 nthcdr with a zero count returns the list unchanged; (nthcdr 0 x) is x nthcdr-zero/bfda713e07890a09/0 -finding nthcdr-small-index warning suspicious fixable=true broad.lisp 4049 nthcdr with a small count has a named cdr accessor; use (cddr …) nthcdr-small-index/f273b4ffe8359de6/0 -finding redundant-body-progn warning suspicious fixable=true broad.lisp 665 progn with 2 forms is a when body; splice its forms in redundant-body-progn/bd91eb5e515cc145/0 -finding empty-let warning suspicious fixable=true broad.lisp 732 let with no bindings is just progn; (let () body) is (progn body) empty-let/6f975d0b4722f4eb/0 -finding redundant-if-nil warning suspicious fixable=true broad.lisp 796 if else branch is a redundant nil; (if c x nil) is (if c x) redundant-if-nil/e883c2a7438b14d9/0 -finding redundant-let-star warning suspicious fixable=true broad.lisp 2559 let* with 1 binding is just let; sequential scope is unused redundant-let-star/a18f256659e1ba9a/0 -finding redundant-funcall warning suspicious fixable=true broad.lisp 867 funcall of #'g is a direct call; (funcall #'g …) is (g …) redundant-funcall/80c1c3159cdf3d87/0 -finding redundant-the warning suspicious fixable=true broad.lisp 939 (the t form) is a vacuous type declaration; it is just form redundant-the/2bac242fe26b506b/0 -finding funcall-lambda warning suspicious fixable=true broad.lisp 1007 funcall of a lambda applies it directly; ((lambda …) …) drops the funcall funcall-lambda/673d7cfe29eecb61/0 -finding sharp-quoted-lambda warning suspicious fixable=true broad.lisp 1084 #' on a lambda is redundant; #'(lambda …) is (lambda …) sharp-quoted-lambda/8265b306d04d5a6a/0 -finding redundant-identity warning suspicious fixable=true broad.lisp 1150 identity returns its argument unchanged; (identity x) is x redundant-identity/05affcb5b7734a90/0 -finding redundant-apply warning suspicious fixable=true broad.lisp 4122 apply of #'g to a literal list is a direct call; use (g …) redundant-apply/f5c33aecf2ade963/0 -finding redundant-eql-test warning suspicious fixable=true broad.lisp 4192 find defaults :test to eql; the explicit :test #'eql is redundant redundant-eql-test/08921075042be6dd/0 -finding redundant-identity-key warning suspicious fixable=true broad.lisp 5452 sort defaults :key to identity; the explicit :key #'identity is redundant redundant-identity-key/0d6a3e2540c960d7/0 -finding negated-when-unless warning suspicious fixable=true broad.lisp 3503 when test is (not …); use unless on the un-negated test negated-when-unless/8cea77f08ec45975/0 -finding negated-comparison warning suspicious fixable=true broad.lisp 5599 negated comparison has a complement operator; use >= negated-comparison/63ee3702a87c2d97/0 -finding negated-if warning suspicious fixable=true broad.lisp 5672 if test is negated; (if (not c) a b) is (if c b a) negated-if/33df133ba8537bf9/0 -finding if-to-or warning suspicious fixable=true broad.lisp 5737 if returns its test or the else; (if x x y) is (or x y) if-to-or/ab61c84ad573df95/0 -finding if-not warning suspicious fixable=true broad.lisp 5800 if with then=nil and else=t is a negation; (if test nil t) is (not test) if-not/62237ccefbf0b61e/0 -finding one-step-arithmetic warning suspicious fixable=true broad.lisp 6155 add/subtract of 1 has a shorthand; use 1+ one-step-arithmetic/044bc8cb6d37fb31/0 -finding one-armed-if warning suspicious fixable=true broad.lisp 3577 if has no else branch; (if test then) is (when test then) one-armed-if/efd043892749780a/0 -finding self-comparison error suspicious fixable=false broad.lisp 7476 eq compares operand status with itself self-comparison/448235d114bbed7c/0 -finding nil-comparison warning suspicious fixable=true broad.lisp 6518 equal against nil is a null test; use (null X) nil-comparison/826bacda3f3e61e2/0 -finding t-comparison warning suspicious fixable=false broad.lisp 7558 eq against t matches only the symbol T, not any true value t-comparison/5e76896e21ed7ee4/0 -finding identical-if-branches error dead-code fixable=false broad.lisp 7607 if branches are identical: (foo x) identical-if-branches/5ea1ac8de34ee4b7/0 -finding constant-if-test warning dead-code fixable=true broad.lisp 6229 if test is the constant t; one branch is dead constant-if-test/026b11490469946b/0 -finding constant-when-test warning dead-code fixable=true broad.lisp 6300 when test is the constant t; the body always runs, so this is a progn constant-when-test/9b0a7978fb01361b/0 -finding if-arity error arity fixable=false broad.lisp 6735 if takes 2 or 3 arguments but has 4 if-arity/312e6de6292b7113/0 -finding the-arity error arity fixable=false broad.lisp 7683 the takes exactly 2 arguments (a type and a form) but has 1 the-arity/1898bfc17b742eda/0 -finding equality-arity warning arity fixable=false broad.lisp 7747 eq takes exactly 2 arguments but has 1 equality-arity/34d47bdb8164b7a4/0 -finding accessor-arity error arity fixable=false broad.lisp 7816 gethash takes 2 or 3 argument(s) but has 1 accessor-arity/b4355bf4eacf6bc5/0 -finding append-list-to-cons warning suspicious fixable=true broad.lisp 1359 a one-element append is just a cons; (append (list x) rest) is (cons x rest) append-list-to-cons/88d7b250cdb0e3fd/0 -finding format-to-string warning suspicious fixable=true broad.lisp 1433 format to a string is just princ-to-string; use (princ-to-string x) format-to-string/39b50b82e8ac11f4/0 -finding format-newline warning suspicious fixable=true broad.lisp 1504 (format t "~%") just writes a newline; use (terpri) format-newline/b36342f1429c38ae/0 -finding redundant-divisor warning suspicious fixable=true broad.lisp 1573 the divisor defaults to 1; (floor x 1) is (floor x) redundant-divisor/ec0523314eb5cfd2/0 -finding duplicate-case-keys error duplicate fixable=false broad.lisp 7885 case repeats key :a (2×) duplicate-case-keys/33bca4c760e6356b/0 -finding quoted-case-key error suspicious fixable=false broad.lisp 7970 case key 'apple is quoted; case keys are not evaluated quoted-case-key/9a7165a51a9415a2/0 -finding quoted-case-key error suspicious fixable=false broad.lisp 7986 case key 'carrot is quoted; case keys are not evaluated quoted-case-key/a3c77c1112303135/0 -finding case-nil-key error dead-code fixable=false broad.lisp 8038 case clause key nil is the empty key list and never matches; use ((nil) …) case-nil-key/2146ba19257dc6ac/0 -finding typecase-nil-key error dead-code fixable=false broad.lisp 8109 typecase clause type nil is the empty type and never matches; use null typecase-nil-key/2146ba19257dc6ac/0 -finding malformed-case-clause error malformed fixable=false broad.lisp 8184 case clause 2 is not a non-empty list malformed-case-clause/af63af4c8601a015/0 -finding malformed-case-clause error malformed fixable=false broad.lisp 8186 case clause :two is not a non-empty list malformed-case-clause/0aa07f4e709cc5f1/0 -finding unreachable-case-clause error dead-code fixable=false broad.lisp 8269 case has 1 unreachable clause(s) after a t/otherwise catch-all unreachable-case-clause/f0fe18a1d1f7cd70/0 -finding exhaustive-case-otherwise error malformed fixable=false broad.lisp 8339 ecase does not permit a t clause (it is exhaustive) exhaustive-case-otherwise/2a99d8e2b6f9f1f7/0 -finding duplicate-cond-tests error duplicate fixable=false broad.lisp 8401 cond repeats test (foo) (2×) duplicate-cond-tests/8e590007a2341d0f/0 -finding unreachable-cond-clause error dead-code fixable=false broad.lisp 8498 cond has 1 unreachable clause(s) after a t clause unreachable-cond-clause/bf880ff3fe6aad2b/0 -finding malformed-cond-clause error malformed fixable=false broad.lisp 8595 cond clause :zero is not a non-empty list malformed-cond-clause/985b7e37a585f76b/0 -finding duplicate-let-bindings error duplicate fixable=false broad.lisp 8630 let binds x more than once (2×) duplicate-let-bindings/786fd22df524c3b4/0 -finding malformed-let-binding error malformed fixable=false broad.lisp 8713 let binding (x 1 y 2) has 4 elements; expected a symbol or (var value) malformed-let-binding/b287ea0350e932c2/0 -finding binds-constant error malformed fixable=false broad.lisp 8789 let cannot bind the constant nil binds-constant/238892383a531bb8/0 -finding binds-constant error malformed fixable=false broad.lisp 8797 let cannot bind the constant :status binds-constant/e7aba77a1dc6c0e4/0 -finding malformed-iteration-spec error malformed fixable=false broad.lisp 8860 dolist spec (x) must be (var form [result]) malformed-iteration-spec/0a94b117f74d8cdc/0 -finding eval-when-situation error malformed fixable=false broad.lisp 8961 eval-when situation :executee is not valid eval-when-situation/db9d83b2f50bfeff/0 -finding duplicate-boolean-operands error duplicate fixable=false broad.lisp 9005 or repeats operand x (2×) duplicate-boolean-operands/20e6cca62d6c6b08/0 -finding dead-boolean-operand error dead-code fixable=false broad.lisp 9086 and short-circuits at literal nil; later operands are dead dead-boolean-operand/3a7c0733832bd30e/0 -finding redundant-boolean-identity warning suspicious fixable=true broad.lisp 6373 and has a redundant t operand; drop it redundant-boolean-identity/6099f3c432a128b2/0 -finding de-morgan warning suspicious fixable=true broad.lisp 6454 and of negations collapses by De Morgan to (not (or …)) de-morgan/59f199d4d6ca0ffc/0 -finding single-operand-boolean warning suspicious fixable=true broad.lisp 3269 and has a single operand; (and X) is just X single-operand-boolean/7e86df9999f069f3/0 -finding single-operand-list-op warning suspicious fixable=true broad.lisp 3346 append of one argument returns it unchanged; (append x) is x single-operand-list-op/6e6fdee3fc4c76f1/0 -finding single-operand-arithmetic warning suspicious fixable=true broad.lisp 3423 * has a single operand; (* X) is just X single-operand-arithmetic/5d68a41993e476ea/0 -finding eql-string-comparison error suspicious fixable=false broad.lisp 9167 eql compares against string literal "root" eql-string-comparison/5df8497b5e9f67a1/0 -finding eql-list-comparison error suspicious fixable=false broad.lisp 9243 eql compares against quoted list literal (:a :b) eql-list-comparison/610ef7b2729acd17/0 -finding eql-search-literal error suspicious fixable=false broad.lisp 9336 member searches for literal "x" with the default eql test; add :test eql-search-literal/96249e1f05669ad0/0 -finding eq-number-comparison error suspicious fixable=true broad.lisp 6587 eq compares against number literal 7 eq-number-comparison/23196700b33d9c59/0 -finding eq-char-comparison error suspicious fixable=true broad.lisp 6662 eq compares against character literal #\a; use eql or char= eq-char-comparison/0372a7cb6b4144bd/0 -finding single-arg-comparison error suspicious fixable=false broad.lisp 9411 < has a single argument; the comparison is always true (missing an operand?) single-arg-comparison/4900cb84bed5a9b8/0 -finding sign-comparison warning suspicious fixable=true broad.lisp 5529 comparison against 0 has a dedicated predicate; use zerop sign-comparison/93d63434e0602a33/0 -finding single-clause-cond warning suspicious fixable=true broad.lisp 2632 single-clause cond with a body is just when; (cond (test a b)) is (when test a b) single-clause-cond/370e08e4584356c3/0 -finding cond-t-clause warning suspicious fixable=true broad.lisp 2705 single t-clause cond is just progn; (cond (t a b)) is (progn a b) cond-t-clause/8c478783d564aef8/0 -finding single-value-bind warning suspicious fixable=true broad.lisp 2994 multiple-value-bind of one variable is just let; (multiple-value-bind (x) f body) is (let ((x f)) body) single-value-bind/aabdcc153cb0635a/0 -finding format-missing-destination error suspicious fixable=false broad.lisp 9483 format destination is the string literal "~a~%"; a nil/t/stream destination is missing format-missing-destination/7a85f56d04f4c6ff/0 -finding literal-place error malformed fixable=false broad.lisp 9560 incf place 5 is a literal and cannot be modified literal-place/7088193b550b4211/0 -finding destructive-literal error suspicious fixable=false broad.lisp 9628 nreverse destructively modifies quoted literal (a b c) (undefined behavior) destructive-literal/5bf9f65d8c2b2acc/0 -finding char-op-string error malformed fixable=false broad.lisp 9711 char= is given string literal "a"; it requires a character (type error) char-op-string/90d896193ca587cd/0 -finding empty-body warning suspicious fixable=false broad.lisp 9778 when has no body; the test/spec runs, then nothing empty-body/713b5add40eb9a23/0 -finding identity-arithmetic warning suspicious fixable=false broad.lisp 9840 + has a redundant identity operand 0 (it does nothing) identity-arithmetic/5957946d13e87c0f/0 -finding verbose-negation warning suspicious fixable=true broad.lisp 1645 negation written the long way; use (- x) verbose-negation/db07057c02c96d6b/0 -finding list-star-to-cons warning suspicious fixable=true broad.lisp 1716 a two-argument list* is just a cons; (list* a b) is (cons a b) list-star-to-cons/8dfbceb8e6484013/0 -finding values-list-of-list warning suspicious fixable=true broad.lisp 1788 values-list of a fresh list is just values; (values-list (list a b)) is (values a b) values-list-of-list/a01fe3b901d6d599/0 -finding redundant-prog1 warning suspicious fixable=true broad.lisp 1862 a prog1 wrapping a single form is just that form; (prog1 x) is x redundant-prog1/d11c68d1c2a8c075/0 -finding subseq-zero warning suspicious fixable=true broad.lisp 1932 a subseq from index 0 copies the whole sequence; (subseq seq 0) is (copy-seq seq) subseq-zero/86623ddc853cc31a/0 -finding car-nthcdr warning suspicious fixable=true broad.lisp 1998 car of an nthcdr is nth; (car (nthcdr n x)) is (nth n x) car-nthcdr/fa5f8068ce51888c/0 -finding car-reverse warning suspicious fixable=true broad.lisp 2063 car of a reverse copies the whole list to read one element; use (car (last x)) car-reverse/358664c82b8eb6c2/0 -finding append-nil warning suspicious fixable=true broad.lisp 2129 append with a nil tail is a fresh copy; (append x nil) is (copy-list x) append-nil/9dcde276136a9a2c/0 -finding multiple-value-list-of-values warning suspicious fixable=true broad.lisp 2194 multiple-value-list of a values form is just list; (multiple-value-list (values a b)) is (list a b) multiple-value-list-of-values/1b4099bfb77b9dcf/0 -finding typep-predicate warning suspicious fixable=true broad.lisp 2278 typep against this type has a dedicated predicate; use (stringp x) typep-predicate/c4524e22023511e4/0 -finding coerce-to-t warning suspicious fixable=true broad.lisp 2348 coerce to type t returns the object unchanged; (coerce x t) is x coerce-to-t/5287c8c7f1849642/0 -finding gethash-default warning suspicious fixable=true broad.lisp 2414 the gethash default is nil; (gethash k h nil) is (gethash k h) gethash-default/f31c83fc13478b4e/0 -finding make-hash-table-test warning suspicious fixable=true broad.lisp 2484 the make-hash-table :test defaults to eql; drop the explicit :test 'eql make-hash-table-test/35479fa9b5b47097/0 -finding zero-divisor warning suspicious fixable=false broad.lisp 9892 / by a literal 0 always signals division-by-zero zero-divisor/bb4a55b5af90f7db/0 -finding duplicate-keyword warning duplicate fixable=false broad.lisp 9959 keyword :x is passed more than once; the leftmost value wins duplicate-keyword/9a11e6557d3eae3f/0 -finding defpackage-quoted warning malformed fixable=false broad.lisp 10031 defpackage does not evaluate its options; drop the quote in the :export clause defpackage-quoted/c37b38bb92c1afca/0 -finding step-zero warning suspicious fixable=false broad.lisp 10103 incf by 0 is a no-op that changes nothing step-zero/d9ce2059b5b3a5cc/0 -finding if-to-unless warning suspicious fixable=true broad.lisp 5861 an if with a nil then-branch is an unless; (if c nil e) is (unless c e) if-to-unless/54bbf94ef24fbf44/0 -finding prog2-to-progn warning suspicious fixable=true broad.lisp 5928 a two-form prog2 is just progn; (prog2 a b) is (progn a b) prog2-to-progn/cfc0af416a06509b/0 -finding handler-case-no-clauses warning suspicious fixable=true broad.lisp 5997 a handler-case with no clauses is just its body; (handler-case x) is x handler-case-no-clauses/e6eca94ec47a803d/0 -finding unwind-protect-no-cleanup warning suspicious fixable=true broad.lisp 6075 an unwind-protect with no cleanup is just its body; (unwind-protect x) is x unwind-protect-no-cleanup/0517ee52f6bcfa89/0 -finding redundant-start-zero warning suspicious fixable=true broad.lisp 4265 find :start defaults to 0; drop the explicit :start 0 redundant-start-zero/204c4a0fd8b6054d/0 -finding redundant-end-nil warning suspicious fixable=true broad.lisp 4340 find :end defaults to nil; drop the explicit :end nil redundant-end-nil/95fb7a788caa4221/0 -finding redundant-from-end-nil warning suspicious fixable=true broad.lisp 4412 find :from-end defaults to nil; drop the explicit :from-end nil redundant-from-end-nil/74a10cdf08c695fc/0 -finding redundant-count-nil warning suspicious fixable=true broad.lisp 4489 remove :count defaults to nil; drop the explicit :count nil redundant-count-nil/b4e4e8611abe92d2/0 -finding string-case-fold warning suspicious fixable=true broad.lisp 4563 case-folding both sides of string= is case-insensitive; use string-equal string-case-fold/35ed4435ec80226f/0 -finding char-case-fold warning suspicious fixable=true broad.lisp 4634 case-folding both sides of char= is case-insensitive; use char-equal char-case-fold/1151e7de6ce93524/0 -finding nested-string-case warning suspicious fixable=true broad.lisp 4703 the outer string case op dominates; the inner one is dead work nested-string-case/e1b50d70e857d80e/0 -finding code-char-char-code warning suspicious fixable=true broad.lisp 4776 code-char of char-code is a round-trip; (code-char (char-code c)) is c code-char-char-code/d64bd87a6ec1dd94/0 -finding last-default-count warning suspicious fixable=true broad.lisp 4850 explicit count of 1 restates last's default; (last x 1) is (last x) last-default-count/ee8e9f6b4ebb33ac/0 -finding butlast-default-count warning suspicious fixable=true broad.lisp 4923 explicit count of 1 restates butlast's default; (butlast x 1) is (butlast x) butlast-default-count/6841ef3bad2f901d/0 -finding make-list-default-element warning suspicious fixable=true broad.lisp 4999 explicit :initial-element nil restates make-list's default; drop it make-list-default-element/091b9e3ccae97a5b/0 -finding parse-integer-default-radix warning suspicious fixable=true broad.lisp 5079 explicit :radix 10 restates parse-integer's default; drop it parse-integer-default-radix/6689082ca07df47e/0 -finding getf-default-nil warning suspicious fixable=true broad.lisp 5161 explicit nil default restates getf's default; (getf p k nil) is (getf p k) getf-default-nil/ccab3d746985ff27/0 -finding make-array-default-keyword warning suspicious fixable=true broad.lisp 5232 explicit :adjustable nil restates make-array's default; drop it make-array-default-keyword/5378b26260ebe135/0 -finding nested-char-case warning suspicious fixable=true broad.lisp 5313 the outer char case op dominates; the inner one is dead work nested-char-case/e5d63774dec3163c/0 -finding list-star-nil warning suspicious fixable=true broad.lisp 5384 list* with a nil tail is a spelled-out list; (list* a b nil) is (list a b) list-star-nil/3d15900073a4c4e4/0 +finding self-assignment error suspicious fixable=false broad.lisp 4273 setq assigns place x to itself self-assignment/5f1a5b802aa99b47/0 +finding duplicate-setf-places error duplicate fixable=false broad.lisp 4321 setf assigns variable total more than once; the earlier assignment is dead duplicate-setf-places/8104810ed815b9fd/0 +finding setf-arity error arity fixable=false broad.lisp 4378 setf has 3 arguments; place/value pairs require an even count setf-arity/b0a5b422aad6d4d2/0 +finding setq-non-variable error malformed fixable=false broad.lisp 4431 setq place (car x) is not a variable setq-non-variable/93a38b0abb06fba2/0 +finding manual-incf warning suspicious fixable=true broad.lisp 2282 setf manually adjusts a variable; use incf manual-incf/e9cc51bb9767dcb7/0 +finding manual-push warning suspicious fixable=true broad.lisp 2317 setf conses onto a variable; use push manual-push/4847791ff6aa61f5/0 +finding manual-pushnew warning suspicious fixable=true broad.lisp 2356 setf adjoins onto a variable; use pushnew manual-pushnew/1e8f91739c283b2f/0 +finding explicit-step-delta warning suspicious fixable=true broad.lisp 1786 incf delta of 1 is the default; (incf x 1) is (incf x) explicit-step-delta/00a1f8d32f2b1a3f/0 +finding negated-step-delta warning suspicious fixable=true broad.lisp 1824 negative delta flips the operator; use decf with a positive delta negated-step-delta/c72d843010c3cb77/0 +finding explicit-nil-return warning suspicious fixable=true broad.lisp 1860 return-from nil result is the default; drop the redundant nil explicit-nil-return/83c6c0866319952f/0 +finding cons-to-list warning suspicious fixable=true broad.lisp 916 cons onto nil/a list is a list constructor; use list cons-to-list/30734641edf18c29/0 +finding double-reverse warning suspicious fixable=true broad.lisp 945 (reverse (reverse x)) is a wasteful copy; use (copy-seq x) double-reverse/64abc2d4def62155/0 +finding modify-macro-arity error arity fixable=false broad.lisp 4463 incf takes 1 or 2 argument(s) but has 3 modify-macro-arity/1c9711db871ff5e7/0 +finding duplicate-parameters error duplicate fixable=false broad.lisp 4504 scale names parameter factor more than once (2×) duplicate-parameters/fc20fd38e853fe41/0 +finding duplicate-lambda-list-keyword error duplicate fixable=false broad.lisp 4575 dupkw repeats lambda-list keyword &optional (2×) duplicate-lambda-list-keyword/2f60a48b9e4ef7e3/0 +finding lambda-list-keyword-order error malformed fixable=false broad.lisp 4652 kworder lists lambda-list keyword &optional after &key lambda-list-keyword-order/617c0a49865251a2/0 +finding redundant-quote warning suspicious fixable=true broad.lisp 437 quoting number 5 is redundant redundant-quote/07bb8307b4864109/0 +finding redundant-progn warning suspicious fixable=true broad.lisp 460 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/a2fdba9820c97822/0 +finding nested-progn warning suspicious fixable=true broad.lisp 507 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/5cd55ce143529b1f/0 +finding nested-when warning suspicious fixable=true broad.lisp 2004 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/3709b9f1558a096d/0 +finding nested-unless warning suspicious fixable=true broad.lisp 2050 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/374f1c05f4fd74ef/0 +finding nested-boolean warning suspicious fixable=true broad.lisp 1974 or nested in a or flattens; its operands splice in nested-boolean/62bd4b586d0045bf/0 +finding nested-cxr warning suspicious fixable=true broad.lisp 2398 nested car/cdr accessors combine into (cadr …) nested-cxr/109a80ae72e5eb4e/0 +finding nth-constant-index warning suspicious fixable=true broad.lisp 2426 nth with a constant index; use (first …) nth-constant-index/9c4d78c87d9ad119/0 +finding nthcdr-zero warning suspicious fixable=true broad.lisp 2459 nthcdr with a zero count returns the list unchanged; (nthcdr 0 x) is x nthcdr-zero/bfda713e07890a09/0 +finding nthcdr-small-index warning suspicious fixable=true broad.lisp 2488 nthcdr with a small count has a named cdr accessor; use (cddr …) nthcdr-small-index/f273b4ffe8359de6/0 +finding redundant-body-progn warning suspicious fixable=true broad.lisp 572 progn with 2 forms is a when body; splice its forms in redundant-body-progn/bd91eb5e515cc145/0 +finding empty-let warning suspicious fixable=true broad.lisp 617 let with no bindings is just progn; (let () body) is (progn body) empty-let/6f975d0b4722f4eb/0 +finding redundant-if-nil warning suspicious fixable=true broad.lisp 655 if else branch is a redundant nil; (if c x nil) is (if c x) redundant-if-nil/e883c2a7438b14d9/0 +finding redundant-let-star warning suspicious fixable=true broad.lisp 1655 let* with 1 binding is just let; sequential scope is unused redundant-let-star/a18f256659e1ba9a/0 +finding redundant-funcall warning suspicious fixable=true broad.lisp 696 funcall of #'g is a direct call; (funcall #'g …) is (g …) redundant-funcall/80c1c3159cdf3d87/0 +finding redundant-the warning suspicious fixable=true broad.lisp 733 (the t form) is a vacuous type declaration; it is just form redundant-the/2bac242fe26b506b/0 +finding funcall-lambda warning suspicious fixable=true broad.lisp 767 funcall of a lambda applies it directly; ((lambda …) …) drops the funcall funcall-lambda/673d7cfe29eecb61/0 +finding sharp-quoted-lambda warning suspicious fixable=true broad.lisp 828 #' on a lambda is redundant; #'(lambda …) is (lambda …) sharp-quoted-lambda/8265b306d04d5a6a/0 +finding redundant-identity warning suspicious fixable=true broad.lisp 881 identity returns its argument unchanged; (identity x) is x redundant-identity/05affcb5b7734a90/0 +finding redundant-apply warning suspicious fixable=true broad.lisp 2524 apply of #'g to a literal list is a direct call; use (g …) redundant-apply/f5c33aecf2ade963/0 +finding redundant-eql-test warning suspicious fixable=true broad.lisp 2564 find defaults :test to eql; the explicit :test #'eql is redundant redundant-eql-test/08921075042be6dd/0 +finding redundant-identity-key warning suspicious fixable=true broad.lisp 3459 sort defaults :key to identity; the explicit :key #'identity is redundant redundant-identity-key/0d6a3e2540c960d7/0 +finding negated-when-unless warning suspicious fixable=true broad.lisp 2211 when test is (not …); use unless on the un-negated test negated-when-unless/8cea77f08ec45975/0 +finding negated-comparison warning suspicious fixable=true broad.lisp 3547 negated comparison has a complement operator; use >= negated-comparison/63ee3702a87c2d97/0 +finding negated-if warning suspicious fixable=true broad.lisp 3583 if test is negated; (if (not c) a b) is (if c b a) negated-if/33df133ba8537bf9/0 +finding if-to-or warning suspicious fixable=true broad.lisp 3622 if returns its test or the else; (if x x y) is (or x y) if-to-or/ab61c84ad573df95/0 +finding if-not warning suspicious fixable=true broad.lisp 3656 if with then=nil and else=t is a negation; (if test nil t) is (not test) if-not/62237ccefbf0b61e/0 +finding one-step-arithmetic warning suspicious fixable=true broad.lisp 3872 add/subtract of 1 has a shorthand; use 1+ one-step-arithmetic/044bc8cb6d37fb31/0 +finding one-armed-if warning suspicious fixable=true broad.lisp 2253 if has no else branch; (if test then) is (when test then) one-armed-if/efd043892749780a/0 +finding self-comparison error suspicious fixable=false broad.lisp 4728 eq compares operand status with itself self-comparison/448235d114bbed7c/0 +finding nil-comparison warning suspicious fixable=true broad.lisp 4062 equal against nil is a null test; use (null X) nil-comparison/826bacda3f3e61e2/0 +finding t-comparison warning suspicious fixable=false broad.lisp 4791 eq against t matches only the symbol T, not any true value t-comparison/5e76896e21ed7ee4/0 +finding identical-if-branches error dead-code fixable=false broad.lisp 4827 if branches are identical: (foo x) identical-if-branches/5ea1ac8de34ee4b7/0 +finding constant-if-test warning dead-code fixable=true broad.lisp 3905 if test is the constant t; one branch is dead constant-if-test/026b11490469946b/0 +finding constant-when-test warning dead-code fixable=true broad.lisp 3947 when test is the constant t; the body always runs, so this is a progn constant-when-test/9b0a7978fb01361b/0 +finding if-arity error arity fixable=false broad.lisp 4160 if takes 2 or 3 arguments but has 4 if-arity/312e6de6292b7113/0 +finding the-arity error arity fixable=false broad.lisp 4886 the takes exactly 2 arguments (a type and a form) but has 1 the-arity/1898bfc17b742eda/0 +finding equality-arity warning arity fixable=false broad.lisp 4912 eq takes exactly 2 arguments but has 1 equality-arity/34d47bdb8164b7a4/0 +finding accessor-arity error arity fixable=false broad.lisp 4937 gethash takes 2 or 3 argument(s) but has 1 accessor-arity/b4355bf4eacf6bc5/0 +finding append-list-to-cons warning suspicious fixable=true broad.lisp 986 a one-element append is just a cons; (append (list x) rest) is (cons x rest) append-list-to-cons/88d7b250cdb0e3fd/0 +finding format-to-string warning suspicious fixable=true broad.lisp 1031 format to a string is just princ-to-string; use (princ-to-string x) format-to-string/39b50b82e8ac11f4/0 +finding format-newline warning suspicious fixable=true broad.lisp 1072 (format t "~%") just writes a newline; use (terpri) format-newline/b36342f1429c38ae/0 +finding redundant-divisor warning suspicious fixable=true broad.lisp 1106 the divisor defaults to 1; (floor x 1) is (floor x) redundant-divisor/ec0523314eb5cfd2/0 +finding duplicate-case-keys error duplicate fixable=false broad.lisp 4969 case repeats key :a (2×) duplicate-case-keys/33bca4c760e6356b/0 +finding quoted-case-key error suspicious fixable=false broad.lisp 5041 case key 'apple is quoted; case keys are not evaluated quoted-case-key/9a7165a51a9415a2/0 +finding quoted-case-key error suspicious fixable=false broad.lisp 5059 case key 'carrot is quoted; case keys are not evaluated quoted-case-key/a3c77c1112303135/0 +finding case-nil-key error dead-code fixable=false broad.lisp 5113 case clause key nil is the empty key list and never matches; use ((nil) …) case-nil-key/2146ba19257dc6ac/0 +finding typecase-nil-key error dead-code fixable=false broad.lisp 5160 typecase clause type nil is the empty type and never matches; use null typecase-nil-key/2146ba19257dc6ac/0 +finding malformed-case-clause error malformed fixable=false broad.lisp 5217 case clause 2 is not a non-empty list malformed-case-clause/af63af4c8601a015/0 +finding malformed-case-clause error malformed fixable=false broad.lisp 5221 case clause :two is not a non-empty list malformed-case-clause/0aa07f4e709cc5f1/0 +finding unreachable-case-clause error dead-code fixable=false broad.lisp 5284 case has 1 unreachable clause(s) after a t/otherwise catch-all unreachable-case-clause/f0fe18a1d1f7cd70/0 +finding exhaustive-case-otherwise error malformed fixable=false broad.lisp 5343 ecase does not permit a t clause (it is exhaustive) exhaustive-case-otherwise/2a99d8e2b6f9f1f7/0 +finding duplicate-cond-tests error duplicate fixable=false broad.lisp 5386 cond repeats test (foo) (2×) duplicate-cond-tests/8e590007a2341d0f/0 +finding unreachable-cond-clause error dead-code fixable=false broad.lisp 5481 cond has 1 unreachable clause(s) after a t clause unreachable-cond-clause/bf880ff3fe6aad2b/0 +finding malformed-cond-clause error malformed fixable=false broad.lisp 5566 cond clause :zero is not a non-empty list malformed-cond-clause/985b7e37a585f76b/0 +finding duplicate-let-bindings error duplicate fixable=false broad.lisp 5598 let binds x more than once (2×) duplicate-let-bindings/786fd22df524c3b4/0 +finding malformed-let-binding error malformed fixable=false broad.lisp 5672 let binding (x 1 y 2) has 4 elements; expected a symbol or (var value) malformed-let-binding/b287ea0350e932c2/0 +finding binds-constant error malformed fixable=false broad.lisp 5725 let cannot bind the constant nil binds-constant/238892383a531bb8/0 +finding binds-constant error malformed fixable=false broad.lisp 5739 let cannot bind the constant :status binds-constant/e7aba77a1dc6c0e4/0 +finding malformed-iteration-spec error malformed fixable=false broad.lisp 5791 dolist spec (x) must be (var form [result]) malformed-iteration-spec/0a94b117f74d8cdc/0 +finding eval-when-situation error malformed fixable=false broad.lisp 5866 eval-when situation :executee is not valid eval-when-situation/db9d83b2f50bfeff/0 +finding duplicate-boolean-operands error duplicate fixable=false broad.lisp 5905 or repeats operand x (2×) duplicate-boolean-operands/20e6cca62d6c6b08/0 +finding dead-boolean-operand error dead-code fixable=false broad.lisp 5946 and short-circuits at literal nil; later operands are dead dead-boolean-operand/3a7c0733832bd30e/0 +finding redundant-boolean-identity warning suspicious fixable=true broad.lisp 3985 and has a redundant t operand; drop it redundant-boolean-identity/6099f3c432a128b2/0 +finding de-morgan warning suspicious fixable=true broad.lisp 4027 and of negations collapses by De Morgan to (not (or …)) de-morgan/59f199d4d6ca0ffc/0 +finding single-operand-boolean warning suspicious fixable=true broad.lisp 2102 and has a single operand; (and X) is just X single-operand-boolean/7e86df9999f069f3/0 +finding single-operand-list-op warning suspicious fixable=true broad.lisp 2136 append of one argument returns it unchanged; (append x) is x single-operand-list-op/6e6fdee3fc4c76f1/0 +finding single-operand-arithmetic warning suspicious fixable=true broad.lisp 2176 * has a single operand; (* X) is just X single-operand-arithmetic/5d68a41993e476ea/0 +finding eql-string-comparison error suspicious fixable=false broad.lisp 6009 eql compares against string literal "root" eql-string-comparison/5df8497b5e9f67a1/0 +finding eql-list-comparison error suspicious fixable=false broad.lisp 6063 eql compares against quoted list literal (:a :b) eql-list-comparison/610ef7b2729acd17/0 +finding eql-search-literal error suspicious fixable=false broad.lisp 6135 member searches for literal "x" with the default eql test; add :test eql-search-literal/96249e1f05669ad0/0 +finding eq-number-comparison error suspicious fixable=true broad.lisp 4094 eq compares against number literal 7 eq-number-comparison/23196700b33d9c59/0 +finding eq-char-comparison error suspicious fixable=true broad.lisp 4127 eq compares against character literal #\a; use eql or char= eq-char-comparison/0372a7cb6b4144bd/0 +finding single-arg-comparison error suspicious fixable=false broad.lisp 6206 < has a single argument; the comparison is always true (missing an operand?) single-arg-comparison/4900cb84bed5a9b8/0 +finding sign-comparison warning suspicious fixable=true broad.lisp 3516 comparison against 0 has a dedicated predicate; use zerop sign-comparison/93d63434e0602a33/0 +finding single-clause-cond warning suspicious fixable=true broad.lisp 1696 single-clause cond with a body is just when; (cond (test a b)) is (when test a b) single-clause-cond/370e08e4584356c3/0 +finding cond-t-clause warning suspicious fixable=true broad.lisp 1738 single t-clause cond is just progn; (cond (t a b)) is (progn a b) cond-t-clause/8c478783d564aef8/0 +finding single-value-bind warning suspicious fixable=true broad.lisp 1907 multiple-value-bind of one variable is just let; (multiple-value-bind (x) f body) is (let ((x f)) body) single-value-bind/aabdcc153cb0635a/0 +finding format-missing-destination error suspicious fixable=false broad.lisp 6273 format destination is the string literal "~a~%"; a nil/t/stream destination is missing format-missing-destination/7a85f56d04f4c6ff/0 +finding literal-place error malformed fixable=false broad.lisp 6343 incf place 5 is a literal and cannot be modified literal-place/7088193b550b4211/0 +finding destructive-literal error suspicious fixable=false broad.lisp 6391 nreverse destructively modifies quoted literal (a b c) (undefined behavior) destructive-literal/5bf9f65d8c2b2acc/0 +finding char-op-string error malformed fixable=false broad.lisp 6464 char= is given string literal "a"; it requires a character (type error) char-op-string/90d896193ca587cd/0 +finding empty-body warning suspicious fixable=false broad.lisp 6534 when has no body; the test/spec runs, then nothing empty-body/713b5add40eb9a23/0 +finding identity-arithmetic warning suspicious fixable=false broad.lisp 6586 + has a redundant identity operand 0 (it does nothing) identity-arithmetic/5957946d13e87c0f/0 +finding verbose-negation warning suspicious fixable=true broad.lisp 1140 negation written the long way; use (- x) verbose-negation/db07057c02c96d6b/0 +finding list-star-to-cons warning suspicious fixable=true broad.lisp 1170 a two-argument list* is just a cons; (list* a b) is (cons a b) list-star-to-cons/8dfbceb8e6484013/0 +finding values-list-of-list warning suspicious fixable=true broad.lisp 1205 values-list of a fresh list is just values; (values-list (list a b)) is (values a b) values-list-of-list/a01fe3b901d6d599/0 +finding redundant-prog1 warning suspicious fixable=true broad.lisp 1255 a prog1 wrapping a single form is just that form; (prog1 x) is x redundant-prog1/d11c68d1c2a8c075/0 +finding subseq-zero warning suspicious fixable=true broad.lisp 1290 a subseq from index 0 copies the whole sequence; (subseq seq 0) is (copy-seq seq) subseq-zero/86623ddc853cc31a/0 +finding car-nthcdr warning suspicious fixable=true broad.lisp 1319 car of an nthcdr is nth; (car (nthcdr n x)) is (nth n x) car-nthcdr/fa5f8068ce51888c/0 +finding car-reverse warning suspicious fixable=true broad.lisp 1354 car of a reverse copies the whole list to read one element; use (car (last x)) car-reverse/358664c82b8eb6c2/0 +finding append-nil warning suspicious fixable=true broad.lisp 1389 append with a nil tail is a fresh copy; (append x nil) is (copy-list x) append-nil/9dcde276136a9a2c/0 +finding multiple-value-list-of-values warning suspicious fixable=true broad.lisp 1420 multiple-value-list of a values form is just list; (multiple-value-list (values a b)) is (list a b) multiple-value-list-of-values/1b4099bfb77b9dcf/0 +finding typep-predicate warning suspicious fixable=true broad.lisp 1492 typep against this type has a dedicated predicate; use (stringp x) typep-predicate/c4524e22023511e4/0 +finding coerce-to-t warning suspicious fixable=true broad.lisp 1531 coerce to type t returns the object unchanged; (coerce x t) is x coerce-to-t/5287c8c7f1849642/0 +finding gethash-default warning suspicious fixable=true broad.lisp 1561 the gethash default is nil; (gethash k h nil) is (gethash k h) gethash-default/f31c83fc13478b4e/0 +finding make-hash-table-test warning suspicious fixable=true broad.lisp 1602 the make-hash-table :test defaults to eql; drop the explicit :test 'eql make-hash-table-test/35479fa9b5b47097/0 +finding zero-divisor warning suspicious fixable=false broad.lisp 6618 / by a literal 0 always signals division-by-zero zero-divisor/bb4a55b5af90f7db/0 +finding duplicate-keyword warning duplicate fixable=false broad.lisp 6642 keyword :x is passed more than once; the leftmost value wins duplicate-keyword/9a11e6557d3eae3f/0 +finding defpackage-quoted warning malformed fixable=false broad.lisp 6692 defpackage does not evaluate its options; drop the quote in the :export clause defpackage-quoted/c37b38bb92c1afca/0 +finding step-zero warning suspicious fixable=false broad.lisp 6746 incf by 0 is a no-op that changes nothing step-zero/d9ce2059b5b3a5cc/0 +finding if-to-unless warning suspicious fixable=true broad.lisp 3688 an if with a nil then-branch is an unless; (if c nil e) is (unless c e) if-to-unless/54bbf94ef24fbf44/0 +finding prog2-to-progn warning suspicious fixable=true broad.lisp 3730 a two-form prog2 is just progn; (prog2 a b) is (progn a b) prog2-to-progn/cfc0af416a06509b/0 +finding handler-case-no-clauses warning suspicious fixable=true broad.lisp 3772 a handler-case with no clauses is just its body; (handler-case x) is x handler-case-no-clauses/e6eca94ec47a803d/0 +finding unwind-protect-no-cleanup warning suspicious fixable=true broad.lisp 3820 an unwind-protect with no cleanup is just its body; (unwind-protect x) is x unwind-protect-no-cleanup/0517ee52f6bcfa89/0 +finding redundant-start-zero warning suspicious fixable=true broad.lisp 2613 find :start defaults to 0; drop the explicit :start 0 redundant-start-zero/204c4a0fd8b6054d/0 +finding redundant-end-nil warning suspicious fixable=true broad.lisp 2661 find :end defaults to nil; drop the explicit :end nil redundant-end-nil/95fb7a788caa4221/0 +finding redundant-from-end-nil warning suspicious fixable=true broad.lisp 2706 find :from-end defaults to nil; drop the explicit :from-end nil redundant-from-end-nil/74a10cdf08c695fc/0 +finding redundant-count-nil warning suspicious fixable=true broad.lisp 2761 remove :count defaults to nil; drop the explicit :count nil redundant-count-nil/b4e4e8611abe92d2/0 +finding string-case-fold warning suspicious fixable=true broad.lisp 2812 case-folding both sides of string= is case-insensitive; use string-equal string-case-fold/35ed4435ec80226f/0 +finding char-case-fold warning suspicious fixable=true broad.lisp 2884 case-folding both sides of char= is case-insensitive; use char-equal char-case-fold/1151e7de6ce93524/0 +finding nested-string-case warning suspicious fixable=true broad.lisp 2948 the outer string case op dominates; the inner one is dead work nested-string-case/e1b50d70e857d80e/0 +finding code-char-char-code warning suspicious fixable=true broad.lisp 3008 code-char of char-code is a round-trip; (code-char (char-code c)) is c code-char-char-code/d64bd87a6ec1dd94/0 +finding last-default-count warning suspicious fixable=true broad.lisp 3059 explicit count of 1 restates last's default; (last x 1) is (last x) last-default-count/ee8e9f6b4ebb33ac/0 +finding butlast-default-count warning suspicious fixable=true broad.lisp 3094 explicit count of 1 restates butlast's default; (butlast x 1) is (butlast x) butlast-default-count/6841ef3bad2f901d/0 +finding make-list-default-element warning suspicious fixable=true broad.lisp 3135 explicit :initial-element nil restates make-list's default; drop it make-list-default-element/091b9e3ccae97a5b/0 +finding parse-integer-default-radix warning suspicious fixable=true broad.lisp 3201 explicit :radix 10 restates parse-integer's default; drop it parse-integer-default-radix/6689082ca07df47e/0 +finding getf-default-nil warning suspicious fixable=true broad.lisp 3262 explicit nil default restates getf's default; (getf p k nil) is (getf p k) getf-default-nil/ccab3d746985ff27/0 +finding make-array-default-keyword warning suspicious fixable=true broad.lisp 3302 explicit :adjustable nil restates make-array's default; drop it make-array-default-keyword/5378b26260ebe135/0 +finding nested-char-case warning suspicious fixable=true broad.lisp 3366 the outer char case op dominates; the inner one is dead work nested-char-case/e5d63774dec3163c/0 +finding list-star-nil warning suspicious fixable=true broad.lisp 3420 list* with a nil tail is a spelled-out list; (list* a b nil) is (list a b) list-star-nil/3d15900073a4c4e4/0 finding declarative-style-score warning suspicious fixable=false broad.lisp 0 this file's declarative-style score is 10% (134 top-level forms), below the 80% threshold declarative-style-score/82af518277a40447/0 -finding leftover-print-debug warning suspicious fixable=false broad.lisp 8864 print is a leftover debug-print call leftover-print-debug/8410f5d691961e8d/0 -finding defpackage-without-in-package warning suspicious fixable=false broad.lisp 10031 package :app is declared but the file never enters it; its 13 definition(s) are interned into whatever package is current, not into :app defpackage-without-in-package/c37b38bb92c1afca/0 -finding return-from-unmatched-block warning suspicious fixable=false broad.lisp 2920 return-from names the block `blk`, which no enclosing form establishes; a block name is lexical return-from-unmatched-block/83c6c0866319952f/0 -finding unused-local-binding warning dead-code fixable=false broad.lisp 8637 local binding `x` bound by `let` is never read in its body; remove it or declare it ignored unused-local-binding/af63f54c86021707/0 -finding unused-local-binding warning dead-code fixable=false broad.lisp 8643 local binding `y` bound by `let` is never read in its body; remove it or declare it ignored unused-local-binding/af63f44c86021554/0 +finding leftover-print-debug warning suspicious fixable=false broad.lisp 5797 print is a leftover debug-print call leftover-print-debug/8410f5d691961e8d/0 +finding defpackage-without-in-package warning suspicious fixable=false broad.lisp 6692 package :app is declared but the file never enters it; its 13 definition(s) are interned into whatever package is current, not into :app defpackage-without-in-package/c37b38bb92c1afca/0 +finding return-from-unmatched-block warning suspicious fixable=false broad.lisp 1860 return-from names the block `blk`, which no enclosing form establishes; a block name is lexical return-from-unmatched-block/83c6c0866319952f/0 +finding unused-local-binding warning dead-code fixable=false broad.lisp 5605 local binding `x` bound by `let` is never read in its body; remove it or declare it ignored unused-local-binding/af63f54c86021707/0 +finding unused-local-binding warning dead-code fixable=false broad.lisp 5617 local binding `y` bound by `let` is never read in its body; remove it or declare it ignored unused-local-binding/af63f44c86021554/0 diff --git a/tests/fixtures/lint_golden/expected/emacs-lisp.fixed.source.golden b/tests/fixtures/lint_golden/expected/emacs-lisp.fixed.source.golden index 7339fbde4..746924e75 100644 --- a/tests/fixtures/lint_golden/expected/emacs-lisp.fixed.source.golden +++ b/tests/fixtures/lint_golden/expected/emacs-lisp.fixed.source.golden @@ -1,10 +1,9 @@ ;;; emacs-lisp.el --- fixture for the Emacs Lisp lint rules - ;; Every rule in `paredit-feature-lint-emacs-lisp` fires here. Line 1 ;; deliberately carries no lexical setting, and the Local Variables block at ;; the end puts one where Emacs will never look for it. - -(defcustom fixture-option nil +(defcustom fixture-option + nil "An option with neither a type nor a group.") (defmacro fixture-macro (n) @@ -14,11 +13,13 @@ (defun fixture-loop () "Use a cl.el name Emacs 27.1 removed." - (loop for n from 1 to 3 collect n)) + (loop for n from 1 to 3 + collect n)) (defun fixture-quoted-lambda () "Return a list that looks like a function." - (lambda (n) n)) + (lambda (n) + n)) (defun fixture-condition-case () "Catch nothing at all." @@ -36,5 +37,4 @@ ;; lexical-binding: t ;; End: ;;; emacs-lisp.el ends here - ;;;###autoload diff --git a/tests/fixtures/lint_golden/expected/emacs-lisp.fixplan.json.golden b/tests/fixtures/lint_golden/expected/emacs-lisp.fixplan.json.golden index 20192e78e..583aaddad 100644 --- a/tests/fixtures/lint_golden/expected/emacs-lisp.fixplan.json.golden +++ b/tests/fixtures/lint_golden/expected/emacs-lisp.fixplan.json.golden @@ -7,15 +7,15 @@ "path": "emacs-lisp.el", "replacements": [ { - "byte_length": 15, - "byte_offset": 621, - "text": "(lambda (n) n)" + "byte_length": 20, + "byte_offset": 629, + "text": "(lambda (n)\n n)" } ], "rule": "elisp-quoted-lambda", "span": { - "end": 636, - "start": 621 + "end": 649, + "start": 629 } } ], diff --git a/tests/fixtures/lint_golden/expected/emacs-lisp.json.golden b/tests/fixtures/lint_golden/expected/emacs-lisp.json.golden index 4e64b3674..75887f8d9 100644 --- a/tests/fixtures/lint_golden/expected/emacs-lisp.json.golden +++ b/tests/fixtures/lint_golden/expected/emacs-lisp.json.golden @@ -36,8 +36,8 @@ "rule": "elisp-unreachable-lexical-binding", "severity": "error", "span": { - "end": 932, - "start": 911 + "end": 945, + "start": 924 } }, { @@ -49,8 +49,8 @@ "rule": "elisp-autoload-cookie-without-form", "severity": "error", "span": { - "end": 762, - "start": 748 + "end": 775, + "start": 761 } }, { @@ -62,8 +62,8 @@ "rule": "elisp-autoload-cookie-without-form", "severity": "error", "span": { - "end": 984, - "start": 970 + "end": 996, + "start": 982 } }, { @@ -76,7 +76,7 @@ "severity": "warning", "span": { "end": 342, - "start": 265 + "start": 263 } }, { @@ -89,7 +89,7 @@ "severity": "warning", "span": { "end": 342, - "start": 265 + "start": 263 } }, { @@ -114,8 +114,8 @@ "rule": "elisp-quoted-lambda", "severity": "error", "span": { - "end": 636, - "start": 621 + "end": 649, + "start": 629 } }, { @@ -140,8 +140,8 @@ "rule": "elisp-condition-case-without-handler", "severity": "error", "span": { - "end": 736, - "start": 700 + "end": 749, + "start": 713 } } ], diff --git a/tests/fixtures/lint_golden/expected/emacs-lisp.sarif.golden b/tests/fixtures/lint_golden/expected/emacs-lisp.sarif.golden index 82ba87ff9..1c5a7a3c3 100644 --- a/tests/fixtures/lint_golden/expected/emacs-lisp.sarif.golden +++ b/tests/fixtures/lint_golden/expected/emacs-lisp.sarif.golden @@ -15,7 +15,7 @@ "byteLength": 92, "byteOffset": 344, "startColumn": 1, - "startLine": 10 + "startLine": 9 } } } @@ -65,9 +65,9 @@ }, "region": { "byteLength": 21, - "byteOffset": 911, + "byteOffset": 924, "startColumn": 1, - "startLine": 36 + "startLine": 37 } } } @@ -91,9 +91,9 @@ }, "region": { "byteLength": 14, - "byteOffset": 748, + "byteOffset": 761, "startColumn": 3, - "startLine": 28 + "startLine": 29 } } } @@ -117,7 +117,7 @@ }, "region": { "byteLength": 14, - "byteOffset": 970, + "byteOffset": 982, "startColumn": 1, "startLine": 40 } @@ -142,10 +142,10 @@ "uri": "emacs-lisp.el" }, "region": { - "byteLength": 77, - "byteOffset": 265, + "byteLength": 79, + "byteOffset": 263, "startColumn": 1, - "startLine": 7 + "startLine": 5 } } } @@ -155,7 +155,7 @@ }, "partialFingerprints": { "pareditFindingId": "elisp-defcustom-missing-type/9fccc736d0e46b79/0", - "primaryLocationLineHash": "fnv1a64:cbbc553bbb93971f:0" + "primaryLocationLineHash": "fnv1a64:e39bd9440eeb4030:0" }, "ruleId": "elisp-defcustom-missing-type" }, @@ -168,10 +168,10 @@ "uri": "emacs-lisp.el" }, "region": { - "byteLength": 77, - "byteOffset": 265, + "byteLength": 79, + "byteOffset": 263, "startColumn": 1, - "startLine": 7 + "startLine": 5 } } } @@ -181,7 +181,7 @@ }, "partialFingerprints": { "pareditFindingId": "elisp-defcustom-missing-group/9fccc736d0e46b79/0", - "primaryLocationLineHash": "fnv1a64:d17a6c91b6493d32:0" + "primaryLocationLineHash": "fnv1a64:73bf40b3a41dad21:0" }, "ruleId": "elisp-defcustom-missing-group" }, @@ -197,7 +197,7 @@ "byteLength": 4, "byteOffset": 505, "startColumn": 4, - "startLine": 17 + "startLine": 16 } } } @@ -207,7 +207,7 @@ }, "partialFingerprints": { "pareditFindingId": "elisp-obsolete-cl-alias/cdece4ad70d57deb/0", - "primaryLocationLineHash": "fnv1a64:8123b7140348beab:0" + "primaryLocationLineHash": "fnv1a64:fb91529381e17321:0" }, "ruleId": "elisp-obsolete-cl-alias" }, @@ -222,11 +222,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 15, - "byteOffset": 621 + "byteLength": 20, + "byteOffset": 629 }, "insertedContent": { - "text": "(lambda (n) n)" + "text": "(lambda (n)\n n)" } } ] @@ -245,8 +245,8 @@ "uri": "emacs-lisp.el" }, "region": { - "byteLength": 15, - "byteOffset": 621, + "byteLength": 20, + "byteOffset": 629, "startColumn": 3, "startLine": 21 } @@ -258,7 +258,7 @@ }, "partialFingerprints": { "pareditFindingId": "elisp-quoted-lambda/d01b8b8f281f7655/0", - "primaryLocationLineHash": "fnv1a64:e73bb58661019248:0" + "primaryLocationLineHash": "fnv1a64:04bacc6104a7cac8:0" }, "ruleId": "elisp-quoted-lambda" }, @@ -274,7 +274,7 @@ "byteLength": 13, "byteOffset": 418, "startColumn": 3, - "startLine": 12 + "startLine": 11 } } } @@ -298,9 +298,9 @@ }, "region": { "byteLength": 36, - "byteOffset": 700, + "byteOffset": 713, "startColumn": 3, - "startLine": 25 + "startLine": 26 } } } diff --git a/tests/fixtures/lint_golden/expected/emacs-lisp.text.golden b/tests/fixtures/lint_golden/expected/emacs-lisp.text.golden index 557f74c3b..dae08c88a 100644 --- a/tests/fixtures/lint_golden/expected/emacs-lisp.text.golden +++ b/tests/fixtures/lint_golden/expected/emacs-lisp.text.golden @@ -343,12 +343,12 @@ rule macro-body-destroys-argument-form 0 rule macrolet-expander-captures-lexical-variable 0 finding elisp-macro-missing-declare warning malformed fixable=false emacs-lisp.el 344 missing editor declaration: macro `fixture-macro` is defined without one; add a leading (declare (indent ...)) and/or (declare (debug ...)) form so Emacs indents and Edebug instruments calls to this macro correctly elisp-macro-missing-declare/3f509c1d426873fb/0 finding elisp-missing-lexical-binding warning suspicious fixable=false emacs-lisp.el 0 no `lexical-binding` setting on the first line, so this file is evaluated with dynamic binding; add `-*- lexical-binding: t -*-` elisp-missing-lexical-binding/48686428ba8a57d0/0 -finding elisp-unreachable-lexical-binding error suspicious fixable=false emacs-lisp.el 911 `lexical-binding` is read from the first line only, so this setting has no effect and the file is evaluated with dynamic binding elisp-unreachable-lexical-binding/7bec796cbb2809fb/0 -finding elisp-autoload-cookie-without-form error suspicious fixable=false emacs-lisp.el 748 this autoload cookie is nested inside a top-level form; `loaddefs` extracts top-level definitions only, so it produces no autoload elisp-autoload-cookie-without-form/1d02fc8f50fffe50/0 -finding elisp-autoload-cookie-without-form error suspicious fixable=false emacs-lisp.el 970 this autoload cookie is followed by no top-level form, so `loaddefs` generation silently produces no autoload for it elisp-autoload-cookie-without-form/1d02fc8f50fffe50/1 -finding elisp-defcustom-missing-type warning malformed fixable=false emacs-lisp.el 265 defcustom fixture-option has no :type, so Customize cannot offer a widget for it elisp-defcustom-missing-type/9fccc736d0e46b79/0 -finding elisp-defcustom-missing-group warning malformed fixable=false emacs-lisp.el 265 defcustom fixture-option has no :group, so its placement in the Customize tree depends on file order elisp-defcustom-missing-group/9fccc736d0e46b79/0 +finding elisp-unreachable-lexical-binding error suspicious fixable=false emacs-lisp.el 924 `lexical-binding` is read from the first line only, so this setting has no effect and the file is evaluated with dynamic binding elisp-unreachable-lexical-binding/7bec796cbb2809fb/0 +finding elisp-autoload-cookie-without-form error suspicious fixable=false emacs-lisp.el 761 this autoload cookie is nested inside a top-level form; `loaddefs` extracts top-level definitions only, so it produces no autoload elisp-autoload-cookie-without-form/1d02fc8f50fffe50/0 +finding elisp-autoload-cookie-without-form error suspicious fixable=false emacs-lisp.el 982 this autoload cookie is followed by no top-level form, so `loaddefs` generation silently produces no autoload for it elisp-autoload-cookie-without-form/1d02fc8f50fffe50/1 +finding elisp-defcustom-missing-type warning malformed fixable=false emacs-lisp.el 263 defcustom fixture-option has no :type, so Customize cannot offer a widget for it elisp-defcustom-missing-type/9fccc736d0e46b79/0 +finding elisp-defcustom-missing-group warning malformed fixable=false emacs-lisp.el 263 defcustom fixture-option has no :group, so its placement in the Customize tree depends on file order elisp-defcustom-missing-group/9fccc736d0e46b79/0 finding elisp-obsolete-cl-alias error suspicious fixable=false emacs-lisp.el 505 `loop` was removed in Emacs 27.1; use `cl-loop` elisp-obsolete-cl-alias/cdece4ad70d57deb/0 -finding elisp-quoted-lambda error suspicious fixable=true emacs-lisp.el 621 a quoted lambda evaluates to a list, not a closure; drop the quote or write `#'` so the body captures its enclosing scope elisp-quoted-lambda/d01b8b8f281f7655/0 +finding elisp-quoted-lambda error suspicious fixable=true emacs-lisp.el 629 a quoted lambda evaluates to a list, not a closure; drop the quote or write `#'` so the body captures its enclosing scope elisp-quoted-lambda/d01b8b8f281f7655/0 finding elisp-interactive-in-macro error suspicious fixable=false emacs-lisp.el 418 macro fixture-macro declares itself interactive, but a macro is expanded rather than called and cannot be a command; `defun` was probably meant elisp-interactive-in-macro/b042d29eb1a42a48/0 -finding elisp-condition-case-without-handler error suspicious fixable=false emacs-lisp.el 700 this condition-case has no handler clauses, so it evaluates its body form and catches nothing elisp-condition-case-without-handler/e02bbaeea25cf9c0/0 +finding elisp-condition-case-without-handler error suspicious fixable=false emacs-lisp.el 713 this condition-case has no handler clauses, so it evaluates its body form and catches nothing elisp-condition-case-without-handler/e02bbaeea25cf9c0/0 diff --git a/tests/fixtures/lint_golden/expected/nested.fixed.source.golden b/tests/fixtures/lint_golden/expected/nested.fixed.source.golden index 3a8838001..aa83e4272 100644 --- a/tests/fixtures/lint_golden/expected/nested.fixed.source.golden +++ b/tests/fixtures/lint_golden/expected/nested.fixed.source.golden @@ -1,7 +1,6 @@ ;; nested.lisp — nested/overlapping forms that exercise fix ordering and ;; fixpoint convergence (a fix on an outer form unlocking a fix on what the ;; rewrite exposes, across several `--fix` passes within one run). - (defun converges-through-progn-then-boolean () x) @@ -14,7 +13,8 @@ (defun deeply-nested-progn () a b - c d + c + d e) (defun overlapping-cxr (x) diff --git a/tests/fixtures/lint_golden/expected/nested.fixplan.json.golden b/tests/fixtures/lint_golden/expected/nested.fixplan.json.golden index 2b7fd7cfe..5e67f74b4 100644 --- a/tests/fixtures/lint_golden/expected/nested.fixplan.json.golden +++ b/tests/fixtures/lint_golden/expected/nested.fixplan.json.golden @@ -8,14 +8,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 840, + "byte_offset": 863, "text": "5" } ], "rule": "redundant-quote", "span": { - "end": 842, - "start": 840 + "end": 865, + "start": 863 } }, { @@ -24,15 +24,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 14, - "byte_offset": 268, + "byte_length": 18, + "byte_offset": 267, "text": "(or x)" } ], "rule": "redundant-progn", "span": { - "end": 282, - "start": 268 + "end": 285, + "start": 267 } }, { @@ -41,15 +41,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 10, - "byte_offset": 833, + "byte_length": 14, + "byte_offset": 852, "text": "'5" } ], "rule": "redundant-progn", "span": { - "end": 843, - "start": 833 + "end": 866, + "start": 852 } }, { @@ -58,15 +58,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 9, - "byte_offset": 907, + "byte_length": 17, + "byte_offset": 936, "text": "a" } ], "rule": "redundant-progn", "span": { - "end": 916, - "start": 907 + "end": 953, + "start": 936 } }, { @@ -75,15 +75,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 33, - "byte_offset": 520, - "text": "b\n (progn c d)" + "byte_length": 49, + "byte_offset": 523, + "text": "b\n (progn\n c\n d)" } ], "rule": "nested-progn", "span": { - "end": 553, - "start": 520 + "end": 572, + "start": 523 } }, { @@ -92,15 +92,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 11, - "byte_offset": 541, - "text": "c d" + "byte_length": 27, + "byte_offset": 544, + "text": "c\n d" } ], "rule": "nested-progn", "span": { - "end": 552, - "start": 541 + "end": 571, + "start": 544 } }, { @@ -110,14 +110,14 @@ "replacements": [ { "byte_length": 50, - "byte_offset": 321, + "byte_offset": 324, "text": "(when (and a b) (when c\n (act)))" } ], "rule": "nested-when", "span": { - "end": 371, - "start": 321 + "end": 374, + "start": 324 } }, { @@ -127,14 +127,14 @@ "replacements": [ { "byte_length": 37, - "byte_offset": 333, + "byte_offset": 336, "text": "(when (and b c) (act))" } ], "rule": "nested-when", "span": { - "end": 370, - "start": 333 + "end": 373, + "start": 336 } }, { @@ -144,14 +144,14 @@ "replacements": [ { "byte_length": 56, - "byte_offset": 412, + "byte_offset": 415, "text": "(unless (or a b) (unless c\n (act)))" } ], "rule": "nested-unless", "span": { - "end": 468, - "start": 412 + "end": 471, + "start": 415 } }, { @@ -161,14 +161,14 @@ "replacements": [ { "byte_length": 41, - "byte_offset": 426, + "byte_offset": 429, "text": "(unless (or b c) (act))" } ], "rule": "nested-unless", "span": { - "end": 467, - "start": 426 + "end": 470, + "start": 429 } }, { @@ -178,14 +178,14 @@ "replacements": [ { "byte_length": 23, - "byte_offset": 768, + "byte_offset": 787, "text": "q (or r (or p q))" } ], "rule": "nested-boolean", "span": { - "end": 791, - "start": 768 + "end": 810, + "start": 787 } }, { @@ -195,14 +195,14 @@ "replacements": [ { "byte_length": 8, - "byte_offset": 781, + "byte_offset": 800, "text": "p q" } ], "rule": "nested-boolean", "span": { - "end": 789, - "start": 781 + "end": 808, + "start": 800 } }, { @@ -212,14 +212,14 @@ "replacements": [ { "byte_length": 19, - "byte_offset": 592, + "byte_offset": 611, "text": "(cadr (cdr x))" } ], "rule": "nested-cxr", "span": { - "end": 611, - "start": 592 + "end": 630, + "start": 611 } }, { @@ -229,14 +229,14 @@ "replacements": [ { "byte_length": 13, - "byte_offset": 597, + "byte_offset": 616, "text": "(cddr x)" } ], "rule": "nested-cxr", "span": { - "end": 610, - "start": 597 + "end": 629, + "start": 616 } }, { @@ -245,15 +245,15 @@ "path": "nested.lisp", "replacements": [ { - "byte_length": 57, - "byte_offset": 503, - "text": "a\n (progn\n b\n (progn c d))\n e" + "byte_length": 73, + "byte_offset": 506, + "text": "a\n (progn\n b\n (progn\n c\n d))\n e" } ], "rule": "redundant-body-progn", "span": { - "end": 560, - "start": 503 + "end": 579, + "start": 506 } }, { @@ -263,14 +263,14 @@ "replacements": [ { "byte_length": 41, - "byte_offset": 678, + "byte_offset": 697, "text": "(step-one)\n (step-two)" } ], "rule": "redundant-body-progn", "span": { - "end": 719, - "start": 678 + "end": 738, + "start": 697 } }, { @@ -280,14 +280,14 @@ "replacements": [ { "byte_length": 7, - "byte_offset": 899, + "byte_offset": 922, "text": "(progn" } ], "rule": "empty-let", "span": { - "end": 917, - "start": 899 + "end": 954, + "start": 922 } }, { @@ -297,14 +297,14 @@ "replacements": [ { "byte_length": 4, - "byte_offset": 882, + "byte_offset": 905, "text": "let" } ], "rule": "redundant-let-star", "span": { - "end": 918, - "start": 881 + "end": 955, + "start": 904 } }, { @@ -314,14 +314,14 @@ "replacements": [ { "byte_length": 6, - "byte_offset": 275, + "byte_offset": 278, "text": "x" } ], "rule": "single-operand-boolean", "span": { - "end": 281, - "start": 275 + "end": 284, + "start": 278 } } ], diff --git a/tests/fixtures/lint_golden/expected/nested.json.golden b/tests/fixtures/lint_golden/expected/nested.json.golden index b3b7999b9..1911c8447 100644 --- a/tests/fixtures/lint_golden/expected/nested.json.golden +++ b/tests/fixtures/lint_golden/expected/nested.json.golden @@ -10,8 +10,8 @@ "rule": "redundant-quote", "severity": "warning", "span": { - "end": 842, - "start": 840 + "end": 865, + "start": 863 } }, { @@ -23,8 +23,8 @@ "rule": "redundant-progn", "severity": "warning", "span": { - "end": 282, - "start": 268 + "end": 285, + "start": 267 } }, { @@ -36,8 +36,8 @@ "rule": "redundant-progn", "severity": "warning", "span": { - "end": 843, - "start": 833 + "end": 866, + "start": 852 } }, { @@ -49,8 +49,8 @@ "rule": "redundant-progn", "severity": "warning", "span": { - "end": 916, - "start": 907 + "end": 953, + "start": 936 } }, { @@ -62,8 +62,8 @@ "rule": "nested-progn", "severity": "warning", "span": { - "end": 553, - "start": 520 + "end": 572, + "start": 523 } }, { @@ -75,8 +75,8 @@ "rule": "nested-progn", "severity": "warning", "span": { - "end": 552, - "start": 541 + "end": 571, + "start": 544 } }, { @@ -88,8 +88,8 @@ "rule": "nested-when", "severity": "warning", "span": { - "end": 371, - "start": 321 + "end": 374, + "start": 324 } }, { @@ -101,8 +101,8 @@ "rule": "nested-when", "severity": "warning", "span": { - "end": 370, - "start": 333 + "end": 373, + "start": 336 } }, { @@ -114,8 +114,8 @@ "rule": "nested-unless", "severity": "warning", "span": { - "end": 468, - "start": 412 + "end": 471, + "start": 415 } }, { @@ -127,8 +127,8 @@ "rule": "nested-unless", "severity": "warning", "span": { - "end": 467, - "start": 426 + "end": 470, + "start": 429 } }, { @@ -140,8 +140,8 @@ "rule": "nested-boolean", "severity": "warning", "span": { - "end": 791, - "start": 768 + "end": 810, + "start": 787 } }, { @@ -153,8 +153,8 @@ "rule": "nested-boolean", "severity": "warning", "span": { - "end": 789, - "start": 781 + "end": 808, + "start": 800 } }, { @@ -166,8 +166,8 @@ "rule": "nested-cxr", "severity": "warning", "span": { - "end": 611, - "start": 592 + "end": 630, + "start": 611 } }, { @@ -179,8 +179,8 @@ "rule": "nested-cxr", "severity": "warning", "span": { - "end": 610, - "start": 597 + "end": 629, + "start": 616 } }, { @@ -192,8 +192,8 @@ "rule": "redundant-body-progn", "severity": "warning", "span": { - "end": 560, - "start": 503 + "end": 579, + "start": 506 } }, { @@ -205,8 +205,8 @@ "rule": "redundant-body-progn", "severity": "warning", "span": { - "end": 719, - "start": 678 + "end": 738, + "start": 697 } }, { @@ -218,8 +218,8 @@ "rule": "empty-let", "severity": "warning", "span": { - "end": 917, - "start": 899 + "end": 954, + "start": 922 } }, { @@ -231,8 +231,8 @@ "rule": "redundant-let-star", "severity": "warning", "span": { - "end": 918, - "start": 881 + "end": 955, + "start": 904 } }, { @@ -244,8 +244,8 @@ "rule": "single-operand-boolean", "severity": "warning", "span": { - "end": 281, - "start": 275 + "end": 284, + "start": 278 } } ], diff --git a/tests/fixtures/lint_golden/expected/nested.sarif.golden b/tests/fixtures/lint_golden/expected/nested.sarif.golden index 4242b6656..2c7b0493a 100644 --- a/tests/fixtures/lint_golden/expected/nested.sarif.golden +++ b/tests/fixtures/lint_golden/expected/nested.sarif.golden @@ -15,7 +15,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 840 + "byteOffset": 863 }, "insertedContent": { "text": "5" @@ -38,9 +38,9 @@ }, "region": { "byteLength": 2, - "byteOffset": 840, - "startColumn": 10, - "startLine": 41 + "byteOffset": 863, + "startColumn": 5, + "startLine": 44 } } } @@ -50,7 +50,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-quote/07bb8307b4864109/0", - "primaryLocationLineHash": "fnv1a64:8ed26b11c3482ced:0" + "primaryLocationLineHash": "fnv1a64:669a337f498e6ef1:0" }, "ruleId": "redundant-quote" }, @@ -65,8 +65,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 14, - "byteOffset": 268 + "byteLength": 18, + "byteOffset": 267 }, "insertedContent": { "text": "(or x)" @@ -88,10 +88,10 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 14, - "byteOffset": 268, + "byteLength": 18, + "byteOffset": 267, "startColumn": 3, - "startLine": 6 + "startLine": 5 } } } @@ -101,7 +101,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-progn/9715182cb9f63314/0", - "primaryLocationLineHash": "fnv1a64:91ba0538b0d7d0f3:0" + "primaryLocationLineHash": "fnv1a64:8b06e00bd2adf89b:0" }, "ruleId": "redundant-progn" }, @@ -116,8 +116,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 10, - "byteOffset": 833 + "byteLength": 14, + "byteOffset": 852 }, "insertedContent": { "text": "'5" @@ -139,10 +139,10 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 10, - "byteOffset": 833, + "byteLength": 14, + "byteOffset": 852, "startColumn": 3, - "startLine": 41 + "startLine": 43 } } } @@ -152,7 +152,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-progn/8d949e5fcf0552a8/0", - "primaryLocationLineHash": "fnv1a64:02cbc6d47036a437:0" + "primaryLocationLineHash": "fnv1a64:8b06e00bd2adf89b:1" }, "ruleId": "redundant-progn" }, @@ -167,8 +167,8 @@ "replacements": [ { "deletedRegion": { - "byteLength": 9, - "byteOffset": 907 + "byteLength": 17, + "byteOffset": 936 }, "insertedContent": { "text": "a" @@ -190,10 +190,10 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 9, - "byteOffset": 907, - "startColumn": 13, - "startLine": 45 + "byteLength": 17, + "byteOffset": 936, + "startColumn": 7, + "startLine": 49 } } } @@ -203,7 +203,7 @@ }, "partialFingerprints": { "pareditFindingId": "redundant-progn/d76c6d3cd567aa37/0", - "primaryLocationLineHash": "fnv1a64:f4153aecbc2fd048:0" + "primaryLocationLineHash": "fnv1a64:8b06e00bd2adf89b:2" }, "ruleId": "redundant-progn" }, @@ -218,11 +218,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 33, - "byteOffset": 520 + "byteLength": 49, + "byteOffset": 523 }, "insertedContent": { - "text": "b\n (progn c d)" + "text": "b\n (progn\n c\n d)" } } ] @@ -241,8 +241,8 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 33, - "byteOffset": 520, + "byteLength": 49, + "byteOffset": 523, "startColumn": 5, "startLine": 23 } @@ -269,11 +269,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 11, - "byteOffset": 541 + "byteLength": 27, + "byteOffset": 544 }, "insertedContent": { - "text": "c d" + "text": "c\n d" } } ] @@ -292,8 +292,8 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 11, - "byteOffset": 541, + "byteLength": 27, + "byteOffset": 544, "startColumn": 7, "startLine": 25 } @@ -305,7 +305,7 @@ }, "partialFingerprints": { "pareditFindingId": "nested-progn/92784ad7b319e3e5/0", - "primaryLocationLineHash": "fnv1a64:5ca6525a04ba0d58:0" + "primaryLocationLineHash": "fnv1a64:237c01a0c789050b:1" }, "ruleId": "nested-progn" }, @@ -321,7 +321,7 @@ { "deletedRegion": { "byteLength": 50, - "byteOffset": 321 + "byteOffset": 324 }, "insertedContent": { "text": "(when (and a b) (when c\n (act)))" @@ -344,7 +344,7 @@ }, "region": { "byteLength": 50, - "byteOffset": 321, + "byteOffset": 324, "startColumn": 3, "startLine": 9 } @@ -372,7 +372,7 @@ { "deletedRegion": { "byteLength": 37, - "byteOffset": 333 + "byteOffset": 336 }, "insertedContent": { "text": "(when (and b c) (act))" @@ -395,7 +395,7 @@ }, "region": { "byteLength": 37, - "byteOffset": 333, + "byteOffset": 336, "startColumn": 5, "startLine": 10 } @@ -423,7 +423,7 @@ { "deletedRegion": { "byteLength": 56, - "byteOffset": 412 + "byteOffset": 415 }, "insertedContent": { "text": "(unless (or a b) (unless c\n (act)))" @@ -446,7 +446,7 @@ }, "region": { "byteLength": 56, - "byteOffset": 412, + "byteOffset": 415, "startColumn": 3, "startLine": 15 } @@ -474,7 +474,7 @@ { "deletedRegion": { "byteLength": 41, - "byteOffset": 426 + "byteOffset": 429 }, "insertedContent": { "text": "(unless (or b c) (act))" @@ -497,7 +497,7 @@ }, "region": { "byteLength": 41, - "byteOffset": 426, + "byteOffset": 429, "startColumn": 5, "startLine": 16 } @@ -525,7 +525,7 @@ { "deletedRegion": { "byteLength": 23, - "byteOffset": 768 + "byteOffset": 787 }, "insertedContent": { "text": "q (or r (or p q))" @@ -548,9 +548,9 @@ }, "region": { "byteLength": 23, - "byteOffset": 768, + "byteOffset": 787, "startColumn": 10, - "startLine": 38 + "startLine": 40 } } } @@ -576,7 +576,7 @@ { "deletedRegion": { "byteLength": 8, - "byteOffset": 781 + "byteOffset": 800 }, "insertedContent": { "text": "p q" @@ -599,9 +599,9 @@ }, "region": { "byteLength": 8, - "byteOffset": 781, + "byteOffset": 800, "startColumn": 23, - "startLine": 38 + "startLine": 40 } } } @@ -627,7 +627,7 @@ { "deletedRegion": { "byteLength": 19, - "byteOffset": 592 + "byteOffset": 611 }, "insertedContent": { "text": "(cadr (cdr x))" @@ -650,9 +650,9 @@ }, "region": { "byteLength": 19, - "byteOffset": 592, + "byteOffset": 611, "startColumn": 3, - "startLine": 29 + "startLine": 31 } } } @@ -678,7 +678,7 @@ { "deletedRegion": { "byteLength": 13, - "byteOffset": 597 + "byteOffset": 616 }, "insertedContent": { "text": "(cddr x)" @@ -701,9 +701,9 @@ }, "region": { "byteLength": 13, - "byteOffset": 597, + "byteOffset": 616, "startColumn": 8, - "startLine": 29 + "startLine": 31 } } } @@ -728,11 +728,11 @@ "replacements": [ { "deletedRegion": { - "byteLength": 57, - "byteOffset": 503 + "byteLength": 73, + "byteOffset": 506 }, "insertedContent": { - "text": "a\n (progn\n b\n (progn c d))\n e" + "text": "a\n (progn\n b\n (progn\n c\n d))\n e" } } ] @@ -751,8 +751,8 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 57, - "byteOffset": 503, + "byteLength": 73, + "byteOffset": 506, "startColumn": 3, "startLine": 21 } @@ -780,7 +780,7 @@ { "deletedRegion": { "byteLength": 41, - "byteOffset": 678 + "byteOffset": 697 }, "insertedContent": { "text": "(step-one)\n (step-two)" @@ -803,9 +803,9 @@ }, "region": { "byteLength": 41, - "byteOffset": 678, + "byteOffset": 697, "startColumn": 5, - "startLine": 33 + "startLine": 35 } } } @@ -831,7 +831,7 @@ { "deletedRegion": { "byteLength": 7, - "byteOffset": 899 + "byteOffset": 922 }, "insertedContent": { "text": "(progn" @@ -853,10 +853,10 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 18, - "byteOffset": 899, + "byteLength": 32, + "byteOffset": 922, "startColumn": 5, - "startLine": 45 + "startLine": 48 } } } @@ -866,7 +866,7 @@ }, "partialFingerprints": { "pareditFindingId": "empty-let/dc954b1687c1363e/0", - "primaryLocationLineHash": "fnv1a64:ccff5780c7da5635:0" + "primaryLocationLineHash": "fnv1a64:5ead522e3c909d98:0" }, "ruleId": "empty-let" }, @@ -882,7 +882,7 @@ { "deletedRegion": { "byteLength": 4, - "byteOffset": 882 + "byteOffset": 905 }, "insertedContent": { "text": "let" @@ -904,10 +904,10 @@ "uri": "nested.lisp" }, "region": { - "byteLength": 37, - "byteOffset": 881, + "byteLength": 51, + "byteOffset": 904, "startColumn": 3, - "startLine": 44 + "startLine": 47 } } } @@ -933,7 +933,7 @@ { "deletedRegion": { "byteLength": 6, - "byteOffset": 275 + "byteOffset": 278 }, "insertedContent": { "text": "x" @@ -956,8 +956,8 @@ }, "region": { "byteLength": 6, - "byteOffset": 275, - "startColumn": 10, + "byteOffset": 278, + "startColumn": 5, "startLine": 6 } } @@ -968,7 +968,7 @@ }, "partialFingerprints": { "pareditFindingId": "single-operand-boolean/242e39c274656eed/0", - "primaryLocationLineHash": "fnv1a64:f917ea298e23b0e6:0" + "primaryLocationLineHash": "fnv1a64:ad3545be4619bc78:0" }, "ruleId": "single-operand-boolean" } diff --git a/tests/fixtures/lint_golden/expected/nested.text.golden b/tests/fixtures/lint_golden/expected/nested.text.golden index 3e8e639b3..01819c2d8 100644 --- a/tests/fixtures/lint_golden/expected/nested.text.golden +++ b/tests/fixtures/lint_golden/expected/nested.text.golden @@ -341,22 +341,22 @@ rule contains-on-non-associative 0 rule reference-type-operator-mismatch 0 rule macro-body-destroys-argument-form 0 rule macrolet-expander-captures-lexical-variable 0 -finding redundant-quote warning suspicious fixable=true nested.lisp 840 quoting number 5 is redundant redundant-quote/07bb8307b4864109/0 -finding redundant-progn warning suspicious fixable=true nested.lisp 268 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/9715182cb9f63314/0 -finding redundant-progn warning suspicious fixable=true nested.lisp 833 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/8d949e5fcf0552a8/0 -finding redundant-progn warning suspicious fixable=true nested.lisp 907 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/d76c6d3cd567aa37/0 -finding nested-progn warning suspicious fixable=true nested.lisp 520 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/32d9beb078a330f2/0 -finding nested-progn warning suspicious fixable=true nested.lisp 541 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/92784ad7b319e3e5/0 -finding nested-when warning suspicious fixable=true nested.lisp 321 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/01c713b3cc5714bd/0 -finding nested-when warning suspicious fixable=true nested.lisp 333 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/47f3cc8d19ddaaf5/0 -finding nested-unless warning suspicious fixable=true nested.lisp 412 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/835cbf88e8f4a683/0 -finding nested-unless warning suspicious fixable=true nested.lisp 426 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/4f88eac26094a26d/0 -finding nested-boolean warning suspicious fixable=true nested.lisp 768 and nested in a and flattens; its operands splice in nested-boolean/f45659592901beaf/0 -finding nested-boolean warning suspicious fixable=true nested.lisp 781 or nested in a or flattens; its operands splice in nested-boolean/d0023e693387d698/0 -finding nested-cxr warning suspicious fixable=true nested.lisp 592 nested car/cdr accessors combine into (cadr …) nested-cxr/711a5272cecca21e/0 -finding nested-cxr warning suspicious fixable=true nested.lisp 597 nested car/cdr accessors combine into (cddr …) nested-cxr/3c85de2e7690aceb/0 -finding redundant-body-progn warning suspicious fixable=true nested.lisp 503 progn with 3 forms is a defun body; splice its forms in redundant-body-progn/cf5441812f2f8395/0 -finding redundant-body-progn warning suspicious fixable=true nested.lisp 678 progn with 2 forms is a when body; splice its forms in redundant-body-progn/656d6b2196b97388/0 -finding empty-let warning suspicious fixable=true nested.lisp 899 let with no bindings is just progn; (let () body) is (progn body) empty-let/dc954b1687c1363e/0 -finding redundant-let-star warning suspicious fixable=true nested.lisp 881 let* with 1 binding is just let; sequential scope is unused redundant-let-star/0f0bdbf55650550e/0 -finding single-operand-boolean warning suspicious fixable=true nested.lisp 275 or has a single operand; (or X) is just X single-operand-boolean/242e39c274656eed/0 +finding redundant-quote warning suspicious fixable=true nested.lisp 863 quoting number 5 is redundant redundant-quote/07bb8307b4864109/0 +finding redundant-progn warning suspicious fixable=true nested.lisp 267 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/9715182cb9f63314/0 +finding redundant-progn warning suspicious fixable=true nested.lisp 852 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/8d949e5fcf0552a8/0 +finding redundant-progn warning suspicious fixable=true nested.lisp 936 redundant progn: progn wraps a single form; it is equivalent to that form redundant-progn/d76c6d3cd567aa37/0 +finding nested-progn warning suspicious fixable=true nested.lisp 523 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/32d9beb078a330f2/0 +finding nested-progn warning suspicious fixable=true nested.lisp 544 progn with 2 forms is nested directly in another progn; splice its forms in nested-progn/92784ad7b319e3e5/0 +finding nested-when warning suspicious fixable=true nested.lisp 324 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/01c713b3cc5714bd/0 +finding nested-when warning suspicious fixable=true nested.lisp 336 when whose only body is a when merges by and; (when a (when b c)) is (when (and a b) c) nested-when/47f3cc8d19ddaaf5/0 +finding nested-unless warning suspicious fixable=true nested.lisp 415 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/835cbf88e8f4a683/0 +finding nested-unless warning suspicious fixable=true nested.lisp 429 unless whose only body is an unless merges by or; (unless a (unless b c)) is (unless (or a b) c) nested-unless/4f88eac26094a26d/0 +finding nested-boolean warning suspicious fixable=true nested.lisp 787 and nested in a and flattens; its operands splice in nested-boolean/f45659592901beaf/0 +finding nested-boolean warning suspicious fixable=true nested.lisp 800 or nested in a or flattens; its operands splice in nested-boolean/d0023e693387d698/0 +finding nested-cxr warning suspicious fixable=true nested.lisp 611 nested car/cdr accessors combine into (cadr …) nested-cxr/711a5272cecca21e/0 +finding nested-cxr warning suspicious fixable=true nested.lisp 616 nested car/cdr accessors combine into (cddr …) nested-cxr/3c85de2e7690aceb/0 +finding redundant-body-progn warning suspicious fixable=true nested.lisp 506 progn with 3 forms is a defun body; splice its forms in redundant-body-progn/cf5441812f2f8395/0 +finding redundant-body-progn warning suspicious fixable=true nested.lisp 697 progn with 2 forms is a when body; splice its forms in redundant-body-progn/656d6b2196b97388/0 +finding empty-let warning suspicious fixable=true nested.lisp 922 let with no bindings is just progn; (let () body) is (progn body) empty-let/dc954b1687c1363e/0 +finding redundant-let-star warning suspicious fixable=true nested.lisp 904 let* with 1 binding is just let; sequential scope is unused redundant-let-star/0f0bdbf55650550e/0 +finding single-operand-boolean warning suspicious fixable=true nested.lisp 278 or has a single operand; (or X) is just X single-operand-boolean/242e39c274656eed/0 diff --git a/tests/fixtures/lint_golden/expected/suppressed.fixed.source.golden b/tests/fixtures/lint_golden/expected/suppressed.fixed.source.golden index e0a18c05d..4320f19c9 100644 --- a/tests/fixtures/lint_golden/expected/suppressed.fixed.source.golden +++ b/tests/fixtures/lint_golden/expected/suppressed.fixed.source.golden @@ -2,13 +2,12 @@ ;; an own-line directive (protects the next line), a trailing directive ;; (protects its own line), a bare directive (silences every rule on the ;; target line), and a multi-rule comma-separated directive. - ;; paredit:ignore redundant-quote (list '5) (list 6) -(< x) ; paredit:ignore single-arg-comparison +(< x) ; paredit:ignore single-arg-comparison ;; paredit:ignore (and (eq y y) '7) diff --git a/tests/fixtures/lint_golden/expected/suppressed.fixplan.json.golden b/tests/fixtures/lint_golden/expected/suppressed.fixplan.json.golden index e798a32fe..79a61baeb 100644 --- a/tests/fixtures/lint_golden/expected/suppressed.fixplan.json.golden +++ b/tests/fixtures/lint_golden/expected/suppressed.fixplan.json.golden @@ -8,14 +8,14 @@ "replacements": [ { "byte_length": 2, - "byte_offset": 338, + "byte_offset": 337, "text": "6" } ], "rule": "redundant-quote", "span": { - "end": 340, - "start": 338 + "end": 339, + "start": 337 } } ], diff --git a/tests/fixtures/lint_golden/expected/suppressed.json.golden b/tests/fixtures/lint_golden/expected/suppressed.json.golden index ede3c97b5..f8ba76008 100644 --- a/tests/fixtures/lint_golden/expected/suppressed.json.golden +++ b/tests/fixtures/lint_golden/expected/suppressed.json.golden @@ -10,8 +10,8 @@ "rule": "redundant-quote", "severity": "warning", "span": { - "end": 340, - "start": 338 + "end": 339, + "start": 337 } }, { @@ -23,7 +23,7 @@ "rule": "declarative-style-score", "severity": "warning", "span": { - "end": 500, + "end": 498, "start": 0 } } diff --git a/tests/fixtures/lint_golden/expected/suppressed.sarif.golden b/tests/fixtures/lint_golden/expected/suppressed.sarif.golden index f688b9a13..59ee895b2 100644 --- a/tests/fixtures/lint_golden/expected/suppressed.sarif.golden +++ b/tests/fixtures/lint_golden/expected/suppressed.sarif.golden @@ -15,7 +15,7 @@ { "deletedRegion": { "byteLength": 2, - "byteOffset": 338 + "byteOffset": 337 }, "insertedContent": { "text": "6" @@ -38,9 +38,9 @@ }, "region": { "byteLength": 2, - "byteOffset": 338, + "byteOffset": 337, "startColumn": 7, - "startLine": 9 + "startLine": 8 } } } @@ -63,7 +63,7 @@ "uri": "suppressed.lisp" }, "region": { - "byteLength": 500, + "byteLength": 498, "byteOffset": 0, "startColumn": 1, "startLine": 1 diff --git a/tests/fixtures/lint_golden/expected/suppressed.text.golden b/tests/fixtures/lint_golden/expected/suppressed.text.golden index 586196799..a20ba02f7 100644 --- a/tests/fixtures/lint_golden/expected/suppressed.text.golden +++ b/tests/fixtures/lint_golden/expected/suppressed.text.golden @@ -341,5 +341,5 @@ rule contains-on-non-associative 0 rule reference-type-operator-mismatch 0 rule macro-body-destroys-argument-form 0 rule macrolet-expander-captures-lexical-variable 0 -finding redundant-quote warning suspicious fixable=true suppressed.lisp 338 quoting number 6 is redundant redundant-quote/07bb8007b4863bf0/0 +finding redundant-quote warning suspicious fixable=true suppressed.lisp 337 quoting number 6 is redundant redundant-quote/07bb8007b4863bf0/0 finding declarative-style-score warning suspicious fixable=false suppressed.lisp 0 this file's declarative-style score is 0% (5 top-level forms), below the 80% threshold declarative-style-score/2f534fdd67304360/0 diff --git a/tests/fixtures/lint_golden/nested.lisp b/tests/fixtures/lint_golden/nested.lisp index 29b43f5ce..149ba1033 100644 --- a/tests/fixtures/lint_golden/nested.lisp +++ b/tests/fixtures/lint_golden/nested.lisp @@ -1,9 +1,9 @@ ;; nested.lisp — nested/overlapping forms that exercise fix ordering and ;; fixpoint convergence (a fix on an outer form unlocking a fix on what the ;; rewrite exposes, across several `--fix` passes within one run). - (defun converges-through-progn-then-boolean () - (progn (or x))) + (progn + (or x))) (defun triple-nested-when (a b c) (when a @@ -22,7 +22,9 @@ a (progn b - (progn c d)) + (progn + c + d)) e)) (defun overlapping-cxr (x) @@ -38,8 +40,11 @@ (and p (and q (or r (or p q))))) (defun nested-quote-inside-progn () - (progn '5)) + (progn + '5)) (defun stacked-redundant-lets () (let* ((a 1)) - (let () (progn a)))) + (let () + (progn + a)))) diff --git a/tests/fixtures/lint_golden/suppressed.lisp b/tests/fixtures/lint_golden/suppressed.lisp index 7155a6a36..96695432e 100644 --- a/tests/fixtures/lint_golden/suppressed.lisp +++ b/tests/fixtures/lint_golden/suppressed.lisp @@ -2,13 +2,12 @@ ;; an own-line directive (protects the next line), a trailing directive ;; (protects its own line), a bare directive (silences every rule on the ;; target line), and a multi-rule comma-separated directive. - ;; paredit:ignore redundant-quote (list '5) (list '6) -(< x) ; paredit:ignore single-arg-comparison +(< x) ; paredit:ignore single-arg-comparison ;; paredit:ignore (and (eq y y) '7) diff --git a/tests/fixtures/sample.el b/tests/fixtures/sample.el index efac5ceee..6e1987b4b 100644 --- a/tests/fixtures/sample.el +++ b/tests/fixtures/sample.el @@ -1 +1,2 @@ -(defun demo (foo) (message "%s" foo)) +(defun demo (foo) + (message "%s" foo)) diff --git a/tests/fixtures/semantic_coverage_corpus/geometry.lisp b/tests/fixtures/semantic_coverage_corpus/geometry.lisp index cd72c5f33..bf9c3e1ee 100644 --- a/tests/fixtures/semantic_coverage_corpus/geometry.lisp +++ b/tests/fixtures/semantic_coverage_corpus/geometry.lisp @@ -1,6 +1,7 @@ (in-package :cl-user) -(defconstant +pi-approx+ 3.14159) +(defconstant +pi-approx+ + 3.14159) (defun circle-area (radius) (let ((r2 (* radius radius))) diff --git a/tests/fixtures/semantic_coverage_corpus/utilities.lisp b/tests/fixtures/semantic_coverage_corpus/utilities.lisp index b2ef23124..a872e7bb2 100644 --- a/tests/fixtures/semantic_coverage_corpus/utilities.lisp +++ b/tests/fixtures/semantic_coverage_corpus/utilities.lisp @@ -1,6 +1,7 @@ (in-package :cl-user) -(defconstant +max-retries+ 3) +(defconstant +max-retries+ + 3) (defun clamp (value low high) (let ((lower (min value high))) From e4f2d1c55cd1b37d1285b00ea0a2fe36b99c87b6 Mon Sep 17 00:00:00 2001 From: takeokunn Date: Sun, 30 Aug 2026 10:24:07 +0900 Subject: [PATCH 4/4] fix: adapt parallel analysis to current path APIs --- packages/core/cli/src/shared.rs | 4 ++-- .../src/shadowed_binding_report/cli/workflow.rs | 2 +- .../src/external_diagnostics_report/cli/workflow.rs | 12 +++++++----- .../src/unused_parameter_report/cli/workflow.rs | 2 +- .../generate/src/generate_defsystem/cli/workflow.rs | 4 ++-- .../generate/src/generate_tests/cli/workflow.rs | 2 +- packages/feature/package/src/package/cli/report.rs | 2 +- .../src/package_boundary_report/cli/workflow.rs | 6 +++++- .../src/call_cycle_report/cli/workflow.rs | 2 +- .../src/call_graph_report/cli/workflow.rs | 2 +- .../project-analysis/src/call_report/cli/workflow.rs | 2 +- .../src/complexity_report/cli/workflow.rs | 2 +- .../src/naming_report/cli/workflow.rs | 2 +- .../src/reachability_report/cli/workflow.rs | 2 +- .../src/signature_report/cli/workflow.rs | 2 +- .../src/unused_local_callable_report/cli/workflow.rs | 2 +- .../src/blame_report/cli/workflow.rs | 2 +- .../src/symbol_report/cli/workflow.rs | 2 +- .../cli/remove_unused_definitions.rs | 2 +- .../src/definition_report/cli/workflow.rs | 4 ++-- .../src/fold_constants/cli/workflow.rs | 2 +- 21 files changed, 34 insertions(+), 28 deletions(-) diff --git a/packages/core/cli/src/shared.rs b/packages/core/cli/src/shared.rs index 067616952..9571b22e1 100644 --- a/packages/core/cli/src/shared.rs +++ b/packages/core/cli/src/shared.rs @@ -973,10 +973,10 @@ where F: Fn(&PathBuf) -> Result + Sync, { let workers = worker_count(files.len()); - let results: Vec> = if workers <= 1 { + let results: Vec> = if workers.get() == 1 { files.iter().map(&process).collect() } else { - analyze_in_parallel_raw(files, &process, workers) + analyze_in_parallel_raw(files, &process, workers.get()) }; let mut analysis = FileAnalysis { diff --git a/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs b/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs index 3cfc6d94a..0612c75ea 100644 --- a/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs +++ b/packages/feature/binding/src/shadowed_binding_report/cli/workflow.rs @@ -16,7 +16,7 @@ pub fn shadowed_binding_report(args: ShadowedBindingReportArgs) -> CommandResult let files = expand_shadowed_binding_report_inputs(&args.files, args.dialect)?; // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { - build_shadowed_binding_report(file.clone(), dialect, &input.text, tree) + build_shadowed_binding_report(file.to_path_buf(), dialect, &input.text, tree) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs b/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs index 4883725f6..11d8453fd 100644 --- a/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs +++ b/packages/feature/external-check/src/external_diagnostics_report/cli/workflow.rs @@ -103,7 +103,7 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma // contract every Common-Lisp-only report in this tool follows. if dialect != Dialect::CommonLisp { return CliResult::Ok(CompileOutcome::SkippedDialect(FileFindings::new( - file.clone(), + file.to_path_buf(), dialect, false, tree.source(), @@ -129,7 +129,7 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma Ok(outcome) => outcome, Err(source) => { return CliResult::Ok(CompileOutcome::RunFailed { - path: file.clone(), + path: file.to_path_buf(), source, }); } @@ -137,7 +137,7 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma if let Some(transcript) = outcome.unparsed_transcript { return CliResult::Ok(CompileOutcome::Unreadable { - path: file.clone(), + path: file.to_path_buf(), exit: outcome .exit_code .map_or_else(|| "signal".to_owned(), |code| code.to_string()), @@ -145,7 +145,9 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma }); } if outcome.timed_out { - return CliResult::Ok(CompileOutcome::TimedOut { path: file.clone() }); + return CliResult::Ok(CompileOutcome::TimedOut { + path: file.to_path_buf(), + }); } let findings = outcome @@ -161,7 +163,7 @@ pub fn external_diagnostics_report(args: ExternalDiagnosticsReportArgs) -> Comma .collect::>(); let report = FileFindings::new( - file.clone(), + file.to_path_buf(), dialect, true, tree.source(), diff --git a/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs b/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs index 67459d4de..da82881d2 100644 --- a/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs +++ b/packages/feature/function-parameter/src/unused_parameter_report/cli/workflow.rs @@ -17,7 +17,7 @@ pub fn unused_parameter_report(args: UnusedParameterReportArgs) -> CommandResult let files = expand_unused_parameter_report_inputs(&args.files, args.dialect)?; // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { - build_unused_parameter_report(file.clone(), dialect, tree, &input.text) + build_unused_parameter_report(file.to_path_buf(), dialect, tree, &input.text) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/generate/src/generate_defsystem/cli/workflow.rs b/packages/feature/generate/src/generate_defsystem/cli/workflow.rs index 9c92c3de7..aaaad926e 100644 --- a/packages/feature/generate/src/generate_defsystem/cli/workflow.rs +++ b/packages/feature/generate/src/generate_defsystem/cli/workflow.rs @@ -31,9 +31,9 @@ pub fn generate_defsystem(args: GenerateDefsystemArgs) -> CliResult<()> { let files = expand_input_files(std::slice::from_ref(&args.directory), args.dialect)?; let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { CliResult::Ok(if dialect == Dialect::CommonLisp { - FileOutcome::Parsed(file.clone(), tree.clone()) + FileOutcome::Parsed(file.to_path_buf(), tree.clone()) } else { - FileOutcome::SkippedDialect(file.clone()) + FileOutcome::SkippedDialect(file.to_path_buf()) }) }); // A generated defsystem is meant to cover every file in the directory; diff --git a/packages/feature/generate/src/generate_tests/cli/workflow.rs b/packages/feature/generate/src/generate_tests/cli/workflow.rs index bf2f56db9..fcf54122f 100644 --- a/packages/feature/generate/src/generate_tests/cli/workflow.rs +++ b/packages/feature/generate/src/generate_tests/cli/workflow.rs @@ -31,7 +31,7 @@ pub fn generate_tests(args: GenerateTestsArgs) -> CliResult<()> { let report = build_test_map_report(file, dialect, tree); FileOutcome::Stubs(build_test_stubs(&report.findings)) } else { - FileOutcome::SkippedDialect(file.clone()) + FileOutcome::SkippedDialect(file.to_path_buf()) }) }); // Generated test stubs are meant to cover every file passed in; silently diff --git a/packages/feature/package/src/package/cli/report.rs b/packages/feature/package/src/package/cli/report.rs index 15575ef83..c6b17b6c7 100644 --- a/packages/feature/package/src/package/cli/report.rs +++ b/packages/feature/package/src/package/cli/report.rs @@ -19,7 +19,7 @@ pub fn package_report(args: PackageReportArgs) -> CliResult<()> { })?; CliResult::Ok(PackageReportFile { - path: file.clone(), + path: file.to_path_buf(), dialect, report, }) diff --git a/packages/feature/package/src/package_boundary_report/cli/workflow.rs b/packages/feature/package/src/package_boundary_report/cli/workflow.rs index 5af53d797..a56b24d8f 100644 --- a/packages/feature/package/src/package_boundary_report/cli/workflow.rs +++ b/packages/feature/package/src/package_boundary_report/cli/workflow.rs @@ -11,7 +11,11 @@ use paredit_core_cli::shared::{analyze_files, note_partial_file_failures, total_ pub fn package_boundary_report(args: PackageBoundaryReportArgs) -> CommandResult { let files = expand_input_files(&args.files, args.dialect)?; let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { - CliResult::Ok(build_package_boundary_report(file.clone(), dialect, tree)?) + CliResult::Ok(build_package_boundary_report( + file.to_path_buf(), + dialect, + tree, + )?) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs index c62687903..59c69107c 100644 --- a/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_cycle_report/cli/workflow.rs @@ -13,7 +13,7 @@ pub fn call_cycle_report(args: CallCycleReportArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { CliResult::Ok(CallGraphReportSource { - path: file.clone(), + path: file.to_path_buf(), dialect, tree: tree.clone(), }) diff --git a/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs index c5244b67e..0b41ea1d8 100644 --- a/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_graph_report/cli/workflow.rs @@ -16,7 +16,7 @@ pub fn call_graph(args: CallGraphArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { CliResult::Ok(CallGraphReportSource { - path: file.clone(), + path: file.to_path_buf(), dialect, tree: tree.clone(), }) diff --git a/packages/feature/project-analysis/src/call_report/cli/workflow.rs b/packages/feature/project-analysis/src/call_report/cli/workflow.rs index c0b60cbb8..c4c051852 100644 --- a/packages/feature/project-analysis/src/call_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/call_report/cli/workflow.rs @@ -17,7 +17,7 @@ pub fn call_report(args: CallReportArgs) -> CommandResult { args.include_definitions, )?; ProjectAnalysisResult::Ok(CallReportFile { - path: file.clone(), + path: file.to_path_buf(), dialect, calls, }) diff --git a/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs b/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs index 7f26a8d8b..2641214f3 100644 --- a/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/complexity_report/cli/workflow.rs @@ -16,7 +16,7 @@ pub fn complexity_report(args: ComplexityReportArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { - build_complexity_report(file.clone(), dialect, tree) + build_complexity_report(file.to_path_buf(), dialect, tree) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/project-analysis/src/naming_report/cli/workflow.rs b/packages/feature/project-analysis/src/naming_report/cli/workflow.rs index ca01ae3a6..4b98c1637 100644 --- a/packages/feature/project-analysis/src/naming_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/naming_report/cli/workflow.rs @@ -16,7 +16,7 @@ pub fn naming_report(args: NamingReportArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { - build_naming_report(file.clone(), dialect, tree) + build_naming_report(file.to_path_buf(), dialect, tree) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs b/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs index 296927775..914d3e50b 100644 --- a/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/reachability_report/cli/workflow.rs @@ -13,7 +13,7 @@ pub fn reachability_report(args: ReachabilityReportArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { CliResult::Ok(CallGraphReportSource { - path: file.clone(), + path: file.to_path_buf(), dialect, tree: tree.clone(), }) diff --git a/packages/feature/project-analysis/src/signature_report/cli/workflow.rs b/packages/feature/project-analysis/src/signature_report/cli/workflow.rs index 8b6ed64b8..93fad7b2e 100644 --- a/packages/feature/project-analysis/src/signature_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/signature_report/cli/workflow.rs @@ -14,7 +14,7 @@ pub fn signature_report(args: SignatureReportArgs) -> CommandResult { // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&args.files, args.dialect, |file, dialect, tree, _| { CliResult::Ok(SignatureReportSource { - path: file.clone(), + path: file.to_path_buf(), dialect, tree: tree.clone(), }) diff --git a/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs b/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs index 5ed0929f2..5a1104e33 100644 --- a/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs +++ b/packages/feature/project-analysis/src/unused_local_callable_report/cli/workflow.rs @@ -17,7 +17,7 @@ pub fn unused_local_callable_report(args: UnusedLocalCallableReportArgs) -> Comm // A file that will not parse is reported, not fatal — see `query find`. let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { - build_unused_local_callable_report(file.clone(), dialect, &input.text, tree) + build_unused_local_callable_report(file.to_path_buf(), dialect, &input.text, tree) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); diff --git a/packages/feature/project-inventory/src/blame_report/cli/workflow.rs b/packages/feature/project-inventory/src/blame_report/cli/workflow.rs index 235cac388..7bc7f15c3 100644 --- a/packages/feature/project-inventory/src/blame_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/blame_report/cli/workflow.rs @@ -14,7 +14,7 @@ pub fn blame_report(args: BlameReportArgs) -> CommandResult { let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _| { // One `git blame` per file, run in the file's own directory so a report // spanning several repositories answers for each of them. - let blame = measure_blame(&file.canonicalize().unwrap_or_else(|_| file.clone())); + let blame = measure_blame(&file.canonicalize().unwrap_or_else(|_| file.to_path_buf())); CliResult::Ok(build_blame_report(file, dialect, tree, &blame)) }); if analysis.is_total_failure() { diff --git a/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs b/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs index 02b6df88e..fdb4f98be 100644 --- a/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs +++ b/packages/feature/project-inventory/src/symbol_report/cli/workflow.rs @@ -47,7 +47,7 @@ pub fn symbol_report(args: SymbolReportArgs) -> CommandResult { .collect::>(); CliResult::Ok(SymbolReportFile { - path: file.clone(), + path: file.to_path_buf(), dialect, occurrences, }) diff --git a/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs b/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs index f55d4b966..69e8587f5 100644 --- a/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs +++ b/packages/feature/remove-unused/src/definition_removal/cli/remove_unused_definitions.rs @@ -24,7 +24,7 @@ pub fn remove_unused_definitions(args: RemoveUnusedDefinitionsArgs) -> CliResult CliResult::Ok(( RemoveUnusedDefinitionInputFile { - path: file.clone(), + path: file.to_path_buf(), dialect, package, definitions: definitions diff --git a/packages/feature/remove-unused/src/definition_report/cli/workflow.rs b/packages/feature/remove-unused/src/definition_report/cli/workflow.rs index f7fa106bd..cfb9db6be 100644 --- a/packages/feature/remove-unused/src/definition_report/cli/workflow.rs +++ b/packages/feature/remove-unused/src/definition_report/cli/workflow.rs @@ -15,7 +15,7 @@ use paredit_core_workspace::workspace::{WorkspaceDiscoveryOptions, discover_work pub fn definition_report(args: DefinitionReportArgs) -> CliResult<()> { let files = expand_definition_report_inputs(&args.files, args.dialect)?; let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, _input| { - CliResult::Ok(build_definition_report(file.clone(), dialect, tree)?) + CliResult::Ok(build_definition_report(file.to_path_buf(), dialect, tree)?) }); if analysis.is_total_failure() { return Err(total_file_failure(analysis.failed).into()); @@ -29,7 +29,7 @@ pub fn unused_definition_report(args: UnusedDefinitionReportArgs) -> CommandResu let files = expand_definition_report_inputs(&args.files, args.dialect)?; let analysis = analyze_files(&files, args.dialect, |file, dialect, tree, input| { CliResult::Ok(build_parsed_definition_file( - file.clone(), + file.to_path_buf(), dialect, tree, &input.text, diff --git a/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs b/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs index 8101ed126..7f540cfa0 100644 --- a/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs +++ b/packages/feature/semantic-report/src/fold_constants/cli/workflow.rs @@ -70,7 +70,7 @@ pub fn fold_constants(args: FoldConstantsArgs) -> CliResult<()> { apply_byte_span_edits(&input.text, edits)? }; CliResult::Ok(FoldPlan { - path: file.clone(), + path: file.to_path_buf(), dialect, before: input.text.clone(), rewritten,