Skip to content

Commit

Permalink
Move fixing logic to cairo-lint-core (#179)
Browse files Browse the repository at this point in the history
* Move fixing logic to cairo-lint-core

* Reexport annotate-snippets

* Make separate function for getting fixes and applying them
  • Loading branch information
wawel37 authored Jan 14, 2025
1 parent 3cd07f3 commit b95a194
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/cairo-lint-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ repository.workspace = true
license-file.workspace = true

[dependencies]
anyhow.workspace = true
cairo-lang-compiler.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-semantic.workspace = true
Expand All @@ -27,3 +28,6 @@ ctor.workspace = true
cairo-lint-test-utils = { path = "../cairo-lint-test-utils" }
paste.workspace = true
itertools.workspace = true

[features]
testing-colors = ["annotate-snippets/testing-colors"]
86 changes: 86 additions & 0 deletions crates/cairo-lint-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,90 @@
use std::{cmp::Reverse, collections::HashMap};

use anyhow::{anyhow, Result};
use cairo_lang_compiler::db::RootDatabase;
use cairo_lang_diagnostics::DiagnosticEntry;
use cairo_lang_filesystem::db::FilesGroup;
use cairo_lang_filesystem::ids::FileId;
use cairo_lang_semantic::{diagnostic::SemanticDiagnosticKind, SemanticDiagnostic};
use cairo_lang_syntax::node::SyntaxNode;
use cairo_lang_utils::Upcast;
use fix::{apply_import_fixes, collect_unused_imports, fix_semantic_diagnostic, Fix, ImportFix};

pub mod diagnostics;
pub mod fix;
pub mod lints;
pub mod plugin;
pub use annotate_snippets;

pub fn get_fixes(
db: &RootDatabase,
diagnostics: Vec<SemanticDiagnostic>,
) -> Result<HashMap<FileId, Vec<Fix>>> {
// Handling unused imports separately as we need to run pre-analysis on the diagnostics.
// to handle complex cases.
let unused_imports: HashMap<FileId, HashMap<SyntaxNode, ImportFix>> =
collect_unused_imports(db, &diagnostics);
let mut fixes = HashMap::new();
unused_imports.keys().for_each(|file_id| {
let file_fixes: Vec<Fix> = apply_import_fixes(db, unused_imports.get(file_id).unwrap());
fixes.insert(*file_id, file_fixes);
});

let diags_without_imports = diagnostics
.iter()
.filter(|diag| !matches!(diag.kind, SemanticDiagnosticKind::UnusedImport(_)))
.collect::<Vec<_>>();

for diag in diags_without_imports {
if let Some((fix_node, fix)) = fix_semantic_diagnostic(db, diag) {
let location = diag.location(db.upcast());
fixes
.entry(location.file_id)
.or_insert_with(Vec::new)
.push(Fix {
span: fix_node.span(db.upcast()),
suggestion: fix,
});
}
}
Ok(fixes)
}

pub fn apply_file_fixes(file_id: FileId, fixes: Vec<Fix>, db: &RootDatabase) -> Result<()> {
let mut fixes = fixes;
fixes.sort_by_key(|fix| Reverse(fix.span.start));
let mut fixable_diagnostics = Vec::with_capacity(fixes.len());
if fixes.len() <= 1 {
fixable_diagnostics = fixes;
} else {
// Check if we have nested diagnostics. If so it's a nightmare to fix hence just ignore it
for i in 0..fixes.len() - 1 {
let first = fixes[i].span;
let second = fixes[i + 1].span;
if first.start >= second.end {
fixable_diagnostics.push(fixes[i].clone());
if i == fixes.len() - 1 {
fixable_diagnostics.push(fixes[i + 1].clone());
}
}
}
}
// Get all the files that need to be fixed
let mut files: HashMap<FileId, String> = HashMap::default();
files.insert(
file_id,
db.file_content(file_id)
.ok_or(anyhow!("{} not found", file_id.file_name(db.upcast())))?
.to_string(),
);
// Fix the files
for fix in fixable_diagnostics {
// Can't fail we just set the file value.
files
.entry(file_id)
.and_modify(|file| file.replace_range(fix.span.to_str_range(), &fix.suggestion));
}
// Dump them in place
std::fs::write(file_id.full_path(db.upcast()), files.get(&file_id).unwrap())?;
Ok(())
}
3 changes: 1 addition & 2 deletions crates/cairo-lint-core/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ impl AnalyzerPlugin for CairoLint {
.as_syntax_node()
}
ModuleItemId::Impl(impl_id) => {
let impl_functions = db.impl_functions(*impl_id);
let Ok(functions) = impl_functions else {
let Ok(functions) = db.impl_functions(*impl_id) else {
continue;
};
for (_fn_name, fn_id) in functions.iter() {
Expand Down

0 comments on commit b95a194

Please sign in to comment.