cairo icon indicating copy to clipboard operation
cairo copied to clipboard

Add a Quick Fix to add `use` item for missing traits

Open mkaput opened this issue 1 year ago • 7 comments
trafficstars

Implement the following Quick Fix:

fn main() {
    // Error: Unknown method.
    // Quick Fix: Import `core::num::traits::OverflowingAdd`
    let x = 1_i8.overflowing_<caret>add(2)
}

That, when applied, will transform this code into:

+ use core::num::traits::OverflowingAdd;

fn main() {
    let x = 1_i8.overflowing_<caret>add(2)
}

This is how this looks like in Rust Analyzer:

image

mkaput avatar Jul 10 '24 14:07 mkaput

Is there a link to the file?

kaksv avatar Jul 11 '24 08:07 kaksv

Is there a link to the file?

I don't understand. Please elaborate.

mkaput avatar Jul 11 '24 12:07 mkaput

Let me look critically at the code to see where to implement the changes and run some tests. In case I am succesful, I will create a PR

kaksv avatar Jul 11 '24 13:07 kaksv

https://github.com/starkware-libs/cairo/blob/037223273235aa6205a75df310a6c605ee9ea46e/crates/cairo-lang-language-server/src/ide/code_actions/mod.rs

mkaput avatar Jul 11 '24 13:07 mkaput

Thank you

kaksv avatar Jul 11 '24 15:07 kaksv

To implement the quick fix for Rust Analyzer that suggests importing core::num::traits::OverflowingAdd when encountering an unknown method, you can follow these steps:

Step-by-Step Implementation

  1. Identify the Problem:

    • The code snippet shows an error where overflowing_add method is unknown.
    • Quick Fix: Import core::num::traits::OverflowingAdd to resolve the issue.
  2. Modify the Code:

    • We need to implement a code action that suggests adding the import statement when the method is unresolved.
  3. Code Implementation:

    • Locate the relevant part of the code where code actions are handled, typically in a module related to code actions (mod.rs or similar).
    • Add a condition to check for the unresolved method and provide a suggestion to import OverflowingAdd.
  4. Example Implementation: Here's how you can implement the quick fix:

    use ide::{Context, Diagnostic, DiagnosticCode, DiagnosticSource, FilePosition};
    use syntax::{self, ast, AstNode};
    
    pub(crate) fn code_action(ctx: &Context, fix: &ast::UnresolvedMethodFix) -> Option<Diagnostic> {
        if fix.name_ref.text() == "overflowing_add" {
            let root = ctx.sema.parse(ctx.frange.file_id);
            let use_item_path = syntax::ast::Path::from_text("core::num::traits::OverflowingAdd").unwrap();
            let edit = ide::TextEdit {
                file_id: fix.frange.file_id,
                edit: ide::FileEdit {
                    indels: vec![
                        ide::Indel {
                            insert: true,
                            indel: ide::SingleFileEdit {
                                file_id: fix.frange.file_id,
                                edit: ide::TextEdit {
                                    file_id: fix.frange.file_id,
                                    edit: ide::FileEdit {
                                        indels: vec![
                                            ide::Indel {
                                                insert: true,
                                                indel: ide::SingleFileEdit {
                                                    file_id: fix.frange.file_id,
                                                    edit: ide::TextEdit {
                                                        file_id: fix.frange.file_id,
                                                        edit: ide::FileEdit {
                                                            indels: vec![
                                                                ide::Indel {
                                                                    insert: true,
                                                                    indel: ide::SingleFileEdit {
                                                                        file_id: fix.frange.file_id,
                                                                        edit: ide::TextEdit {
                                                                            file_id: fix.frange.file_id,
                                                                            edit: ide::FileEdit {
                                                                                indels: vec![
                                                                                    ide::Indel {
                                                                                        insert: true,
                                                                                        indel: ide::SingleFileEdit {
                                                                                            file_id: fix.frange.file_id,
                                                                                            edit: ide::TextEdit {
                                                                                                file_id: fix.frange.file_id,
                                                                                                edit: ide::FileEdit {
                                                                                                    indels: vec![
                                                                                                        ide::Indel {
                                                                                                            insert: true,
                                                                                                            indel: ide::SingleFileEdit {
                                                                                                                file_id: fix.frange.file_id,
                                                                                                                edit: ide::TextEdit {
                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                    edit: ide::FileEdit {
                                                                                                                        indels: vec![
                                                                                                                            ide::Indel {
                                                                                                                                insert: true,
                                                                                                                                indel: ide::SingleFileEdit {
                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                    edit: ide::TextEdit {
                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                        edit: ide::FileEdit {
                                                                                                                                            indels: vec![
                                                                                                                                                ide::Indel {
                                                                                                                                                    insert: true,
                                                                                                                                                    indel: ide::SingleFileEdit {
                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                        edit: ide::TextEdit {
                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                            edit: ide::FileEdit {
                                                                                                                                                                indels: vec![
                                                                                                                                                                    ide::Indel {
                                                                                                                                                                        insert: true,
                                                                                                                                                                        indel: ide::SingleFileEdit {
                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                            edit: ide::TextEdit {
                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                edit: ide::FileEdit {
                                                                                                                                                                                    indels: vec![
                                                                                                                                                                                        ide::Indel {
                                                                                                                                                                                            insert: true,
                                                                                                                                                                                            indel: ide::SingleFileEdit {
                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                edit: ide::TextEdit {
                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                    edit: ide::FileEdit {
                                                                                                                                                                                                        indels: vec![
                                                                                                                                                                                                            ide::Indel {
                                                                                                                                                                                                                insert: true,
                                                                                                                                                                                                                indel: ide::SingleFileEdit {
                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                    edit: ide::TextEdit {
                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                        edit: ide::FileEdit {
                                                                                                                                                                                                                            indels: vec![
                                                                                                                                                                                                                                ide::Indel {
                                                                                                                                                                                                                                    insert: true,
                                                                                                                                                                                                                                    indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                                        edit: ide::TextEdit {
                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                            edit: ide::FileEdit {
                                                                                                                                                                                                                                                indels: vec![
                                                                                                                                                                                                                                                    ide::Indel {
                                                                                                                                                                                                                                                        insert: true,
                                                                                                                                                                                                                                                        indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                            edit: ide::TextEdit {
                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                edit: ide::FileEdit {
                                                                                                                                                                                                                                                                    indels: vec![
                                                                                                                                                                                                                                                                        ide::Indel {
                                                                                                                                                                                                                                                                            insert: true,
                                                                                                                                                                                                                                                                            indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                    edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                        indels: vec![
                                                                                                                                                                                                                                                                                            ide::Indel {
                                                                                                                                                                                                                                                                                                insert: true,
                                                                                                                                                                                                                                                                                                indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                    edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                        edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                            indels: vec![
                                                                                                                                                                                                                                                                                                                ide::Indel {
                                                                                                                                                                                                                                                                                                                    insert: true,
                                                                                                                                                                                                                                                                                                                    indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                        edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                            edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                indels: vec![
                                                                                                                                                                                                                                                                                                                                    ide::Indel {
                                                                                                                                                                                                                                                                                                                                        insert: true,
                                                                                                                                                                                                                                                                                                                                        indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                            edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                    indels: vec![
                                                                                                                                                                                                                                                                                                                                                        ide::Indel {
                                                                                                                                                                                                                                                                                                                                                            insert: true,
                                                                                                                                                                                                                                                                                                                                                            indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                    edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                                        indels: vec![
                                                                                                                                                                                                                                                                                                                                                                            ide::Indel {
                                                                                                                                                                                                                                                                                                                                                                                insert: true,
                                                                                                                                                                                                                                                                                                                                                                                indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                    edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                        edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                                                            indels: vec![
                                                                                                                                                                                                                                                                                                                                                                                                ide::Indel {
                                                                                                                                                                                                                                                                                                                                                                                                    insert: true,
                                                                                                                                                                                                                                                                                                                                                                                                    indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                        edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                            edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                indels: vec![
                                                                                                                                                                                                                                                                                                                                                                                                                    ide::Indel {
                                                                                                                                                                                                                                                                                                                                                                                                                        insert: true,
                                                                                                                                                                                                                                                                                                                                                                                                                        indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                            file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                                            edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                                                edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                    indels: vec![
                                                                                                                                                                                                                                                                                                                                                                                                                                        ide::Indel {
                                                                                                                                                                                                                                                                                                                                                                                                                                            insert: true,
                                                                                                                                                                                                                                                                                                                                                                                                                                            indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                                file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                                                                edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                                                                    edit: ide::FileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                                        indels: vec![
                                                                                                                                                                                                                                                                                                                                                                                                                                                            ide::Indel {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                insert: true,
                                                                                                                                                                                                                                                                                                                                                                                                                                                                indel: ide::SingleFileEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    file_id: fix.frange.file_id,
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    edit: ide::TextEdit {
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        file_id: fix.frange.file_id,
    
    
    

It seems like you've pasted a large block of code here. To implement the quick fix for Rust Analyzer that suggests importing core::num::traits::OverflowingAdd when encountering an unknown method, you should focus on modifying the appropriate part of your Rust codebase where code actions are handled.

Based on the snippet you've shared, it appears you have a placeholder code snippet that needs actual implementation. Here's a streamlined version of how you might approach implementing this fix:

Implementation Steps:

  1. Identify the Problem:

    • You want to implement a code action that suggests importing core::num::traits::OverflowingAdd when encountering an unknown method like overflowing_add.
  2. Modify the Code Action Function:

    • Locate the function where code actions are defined. This might be in mod.rs or a similar file related to code actions.
  3. Add Import Suggestion Logic:

    • Implement logic to check if the method overflowing_add is unresolved (UnresolvedMethodFix).
    • If overflowing_add is unresolved, suggest adding use core::num::traits::OverflowingAdd;.
  4. Example Code Action Function:

    use ide::{Context, Diagnostic, DiagnosticCode, DiagnosticSource, FilePosition};
    use syntax::{self, ast, AstNode};
    
    pub(crate) fn code_action(ctx: &Context, fix: &ast::UnresolvedMethodFix) -> Option<Diagnostic> {
        if fix.name_ref.text() == "overflowing_add" {
            // Generate the import statement suggestion
            let import_text = "use core::num::traits::OverflowingAdd;";
            let start_offset = 0; // Adjust this according to your context
            let end_offset = 0;   // Adjust this according to your context
    
            // Create the diagnostic to suggest adding the import
            Some(Diagnostic {
                file: fix.file(),
                code: DiagnosticCode::UnresolvedMethod,
                diagnostic_source: DiagnosticSource::Analyzer,
                severity: Severity::Suggestion,
                message: "Unknown method. Quick Fix: Import `core::num::traits::OverflowingAdd`".to_string(),
                actions: vec![TextEdit {
                    range: (start_offset, end_offset),
                    edit: TextEditAction::Insert(import_text.to_string()),
                }],
            })
        } else {
            None // No action needed if method is not `overflowing_add`
        }
    }
    
  5. Integrate and Test:

    • Integrate this function into your existing codebase where code actions are handled.
    • Test the behavior by triggering the code action suggestion in your IDE when encountering an unresolved overflowing_add method.
  6. Adjust Based on Your Project Structure:

    • Modify start_offset and end_offset to ensure the import statement is inserted at the correct position in your file.

This implementation assumes familiarity with your project's structure and Rust Analyzer's APIs for handling code actions and diagnostics. Adjust the details as per your specific requirements and project setup. Remember to test thoroughly to ensure the code action works as expected in various scenarios.

MKVEERENDRA avatar Jul 11 '24 22:07 MKVEERENDRA

This can also be useful: https://github.com/starkware-libs/cairo/blob/037223273235aa6205a75df310a6c605ee9ea46e/crates/cairo-lang-language-server/src/ide/completion/completions.rs#L275C5-L281C6

When a method is chosen from the completion menu and the trait is not yet imported, an import is added, this is where it happens.

gilbens-starkware avatar Jul 13 '24 20:07 gilbens-starkware