aboutsummaryrefslogtreecommitdiff
path: root/mingling_cli/src/linter
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-21 16:56:39 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-21 16:56:39 +0800
commitb9d7b8736062509f1f7a5c02943398975ea7ee53 (patch)
tree092c2e69af569522051056008f3b3079f14a0efb /mingling_cli/src/linter
parent05a06b59d2a27428d253308f067aa0e5a841eb5e (diff)
feat(lint): add non_mingling_naming_style lint with auto-fix suggestions
Support file-level lint checks via `check_file` in lint registry template.
Diffstat (limited to 'mingling_cli/src/linter')
-rw-r--r--mingling_cli/src/linter/mlint_report.rs40
1 files changed, 37 insertions, 3 deletions
diff --git a/mingling_cli/src/linter/mlint_report.rs b/mingling_cli/src/linter/mlint_report.rs
index 07fc5c1..8195f77 100644
--- a/mingling_cli/src/linter/mlint_report.rs
+++ b/mingling_cli/src/linter/mlint_report.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
use cargo_metadata::diagnostic::{
DiagnosticCodeBuilder, DiagnosticLevel as CargoLevel, DiagnosticSpanBuilder,
DiagnosticSpanLineBuilder,
@@ -6,7 +8,7 @@ use cargo_metadata::diagnostic::{
use cargo_metadata::{Message, PackageId};
use annotate_snippets::level::{ERROR, HELP, NOTE, WARNING};
-use annotate_snippets::{AnnotationKind, Group, Renderer, Snippet};
+use annotate_snippets::{AnnotationKind, Group, Patch, Renderer, Snippet};
use mingling::macros::{buffer, chain, pack, r_append, r_eprintln, renderer};
use mingling::{AnyOutput, ProgramCollect, Routable};
@@ -48,6 +50,9 @@ pub struct MlintReport {
/// Compilation target source file path that this report belongs to
pub target_src_path: Option<String>,
+
+ /// A suggestion for automatic fix (shown as diff in annotated output)
+ pub suggestion: Option<LintSuggestion>,
}
/// Report severity level, indicating the seriousness of the Lint result.
@@ -86,6 +91,19 @@ pub struct LintSpanLine {
pub highlight_end: usize,
}
+/// A suggestion shown as a diff in the output (e.g. `- old code` / `+ new code`).
+#[derive(Clone, Debug, Default)]
+pub struct LintSuggestion {
+ /// Source text that the suggestion applies to (a single line or snippet)
+ pub source: String,
+ /// Line number where the suggestion applies
+ pub line_start: usize,
+ /// Byte range within `source` to replace
+ pub byte_range: Range<usize>,
+ /// Replacement text
+ pub replacement: String,
+}
+
impl MlintReport {
/// Build a `LintSpan` from a syn spanned item and the source text.
pub fn span_from_syn<T: syn::spanned::Spanned>(value: &T, source: &str) -> LintSpan {
@@ -230,6 +248,18 @@ impl MlintReport {
group = group.element(msg);
}
+ // Render suggestion as a diff (Element::Suggestion)
+ if let Some(sugg) = &self.suggestion {
+ let patch_snippet = Snippet::source(sugg.source.clone())
+ .line_start(sugg.line_start)
+ .path(&self.file_name)
+ .patch(Patch::new(
+ sugg.byte_range.clone(),
+ sugg.replacement.clone(),
+ ));
+ group = group.element(patch_snippet);
+ }
+
if !self.lint_code.is_empty() {
let level_name = match self.level {
MlintLevel::Error => "deny",
@@ -374,8 +404,12 @@ impl MlintReport {
.collect::<Vec<_>>(),
)
.label(span.label.clone())
- .suggested_replacement(None::<String>)
- .suggestion_applicability(None::<cargo_metadata::diagnostic::Applicability>)
+ .suggested_replacement(self.suggestion.as_ref().map(|s| s.replacement.clone()))
+ .suggestion_applicability(if self.suggestion.is_some() {
+ Some(cargo_metadata::diagnostic::Applicability::MachineApplicable)
+ } else {
+ None
+ })
.expansion(None)
.build()
.unwrap()