]> git.lizzy.rs Git - rust.git/commitdiff
Minor
authorAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 18 Aug 2020 14:22:01 +0000 (16:22 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 18 Aug 2020 14:22:01 +0000 (16:22 +0200)
crates/ide/src/diagnostics.rs
crates/ide/src/diagnostics/diagnostics_with_fix.rs [deleted file]
crates/ide/src/diagnostics/fixes.rs [new file with mode: 0644]
crates/ide/src/lib.rs

index 89ff554908a12cfd2d939262d06b8511c788f9db..1f85805d223aebbed16e03700231af4a2d665fc3 100644 (file)
@@ -4,7 +4,7 @@
 //! macro-expanded files, but we need to present them to the users in terms of
 //! original files. So we need to map the ranges.
 
-mod diagnostics_with_fix;
+mod fixes;
 
 use std::cell::RefCell;
 
 };
 use text_edit::TextEdit;
 
-use crate::{Diagnostic, FileId, Fix, SourceFileEdit};
+use crate::{FileId, SourceChange, SourceFileEdit};
 
-use self::diagnostics_with_fix::DiagnosticWithFix;
+use self::fixes::DiagnosticWithFix;
+
+#[derive(Debug)]
+pub struct Diagnostic {
+    pub name: Option<String>,
+    pub message: String,
+    pub range: TextRange,
+    pub severity: Severity,
+    pub fix: Option<Fix>,
+}
+
+#[derive(Debug)]
+pub struct Fix {
+    pub label: String,
+    pub source_change: SourceChange,
+    /// Allows to trigger the fix only when the caret is in the range given
+    pub fix_trigger_range: TextRange,
+}
+
+impl Fix {
+    fn new(
+        label: impl Into<String>,
+        source_change: SourceChange,
+        fix_trigger_range: TextRange,
+    ) -> Self {
+        let label = label.into();
+        assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.'));
+        Self { label, source_change, fix_trigger_range }
+    }
+}
 
 #[derive(Debug, Copy, Clone)]
 pub enum Severity {
diff --git a/crates/ide/src/diagnostics/diagnostics_with_fix.rs b/crates/ide/src/diagnostics/diagnostics_with_fix.rs
deleted file mode 100644 (file)
index 85b46c9..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-//! Provides a way to attach fixes to the diagnostics.
-//! The same module also has all curret custom fixes for the diagnostics implemented.
-use crate::Fix;
-use ast::{edit::IndentLevel, make};
-use base_db::FileId;
-use hir::{
-    db::AstDatabase,
-    diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule},
-    HasSource, HirDisplay, Semantics, VariantDef,
-};
-use ide_db::{
-    source_change::{FileSystemEdit, SourceFileEdit},
-    RootDatabase,
-};
-use syntax::{algo, ast, AstNode};
-use text_edit::TextEdit;
-
-/// A [Diagnostic] that potentially has a fix available.
-///
-/// [Diagnostic]: hir::diagnostics::Diagnostic
-pub trait DiagnosticWithFix: Diagnostic {
-    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
-}
-
-impl DiagnosticWithFix for UnresolvedModule {
-    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
-        let root = sema.db.parse_or_expand(self.file)?;
-        let unresolved_module = self.decl.to_node(&root);
-        Some(Fix::new(
-            "Create module",
-            FileSystemEdit::CreateFile {
-                anchor: self.file.original_file(sema.db),
-                dst: self.candidate.clone(),
-            }
-            .into(),
-            unresolved_module.syntax().text_range(),
-        ))
-    }
-}
-
-impl DiagnosticWithFix for NoSuchField {
-    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
-        let root = sema.db.parse_or_expand(self.file)?;
-        missing_record_expr_field_fix(
-            &sema,
-            self.file.original_file(sema.db),
-            &self.field.to_node(&root),
-        )
-    }
-}
-
-impl DiagnosticWithFix for MissingFields {
-    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
-        // Note that although we could add a diagnostics to
-        // fill the missing tuple field, e.g :
-        // `struct A(usize);`
-        // `let a = A { 0: () }`
-        // but it is uncommon usage and it should not be encouraged.
-        if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
-            return None;
-        }
-
-        let root = sema.db.parse_or_expand(self.file)?;
-        let old_field_list = self.field_list_parent.to_node(&root).record_expr_field_list()?;
-        let mut new_field_list = old_field_list.clone();
-        for f in self.missed_fields.iter() {
-            let field =
-                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
-            new_field_list = new_field_list.append_field(&field);
-        }
-
-        let edit = {
-            let mut builder = TextEdit::builder();
-            algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
-                .into_text_edit(&mut builder);
-            builder.finish()
-        };
-        Some(Fix::new(
-            "Fill struct fields",
-            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(),
-            sema.original_range(&old_field_list.syntax()).range,
-        ))
-    }
-}
-
-impl DiagnosticWithFix for MissingOkInTailExpr {
-    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
-        let root = sema.db.parse_or_expand(self.file)?;
-        let tail_expr = self.expr.to_node(&root);
-        let tail_expr_range = tail_expr.syntax().text_range();
-        let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
-        let source_change =
-            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
-        Some(Fix::new("Wrap with ok", source_change, tail_expr_range))
-    }
-}
-
-fn missing_record_expr_field_fix(
-    sema: &Semantics<RootDatabase>,
-    usage_file_id: FileId,
-    record_expr_field: &ast::RecordExprField,
-) -> Option<Fix> {
-    let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
-    let def_id = sema.resolve_variant(record_lit)?;
-    let module;
-    let def_file_id;
-    let record_fields = match VariantDef::from(def_id) {
-        VariantDef::Struct(s) => {
-            module = s.module(sema.db);
-            let source = s.source(sema.db);
-            def_file_id = source.file_id;
-            let fields = source.value.field_list()?;
-            record_field_list(fields)?
-        }
-        VariantDef::Union(u) => {
-            module = u.module(sema.db);
-            let source = u.source(sema.db);
-            def_file_id = source.file_id;
-            source.value.record_field_list()?
-        }
-        VariantDef::EnumVariant(e) => {
-            module = e.module(sema.db);
-            let source = e.source(sema.db);
-            def_file_id = source.file_id;
-            let fields = source.value.field_list()?;
-            record_field_list(fields)?
-        }
-    };
-    let def_file_id = def_file_id.original_file(sema.db);
-
-    let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
-    if new_field_type.is_unknown() {
-        return None;
-    }
-    let new_field = make::record_field(
-        record_expr_field.field_name()?,
-        make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
-    );
-
-    let last_field = record_fields.fields().last()?;
-    let last_field_syntax = last_field.syntax();
-    let indent = IndentLevel::from_node(last_field_syntax);
-
-    let mut new_field = new_field.to_string();
-    if usage_file_id != def_file_id {
-        new_field = format!("pub(crate) {}", new_field);
-    }
-    new_field = format!("\n{}{}", indent, new_field);
-
-    let needs_comma = !last_field_syntax.to_string().ends_with(',');
-    if needs_comma {
-        new_field = format!(",{}", new_field);
-    }
-
-    let source_change = SourceFileEdit {
-        file_id: def_file_id,
-        edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
-    };
-    return Some(Fix::new(
-        "Create field",
-        source_change.into(),
-        record_expr_field.syntax().text_range(),
-    ));
-
-    fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
-        match field_def_list {
-            ast::FieldList::RecordFieldList(it) => Some(it),
-            ast::FieldList::TupleFieldList(_) => None,
-        }
-    }
-}
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
new file mode 100644 (file)
index 0000000..68ae1c2
--- /dev/null
@@ -0,0 +1,175 @@
+//! Provides a way to attach fixes to the diagnostics.
+//! The same module also has all curret custom fixes for the diagnostics implemented.
+use base_db::FileId;
+use hir::{
+    db::AstDatabase,
+    diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule},
+    HasSource, HirDisplay, Semantics, VariantDef,
+};
+use ide_db::{
+    source_change::{FileSystemEdit, SourceFileEdit},
+    RootDatabase,
+};
+use syntax::{
+    algo,
+    ast::{self, edit::IndentLevel, make},
+    AstNode,
+};
+use text_edit::TextEdit;
+
+use crate::diagnostics::Fix;
+
+/// A [Diagnostic] that potentially has a fix available.
+///
+/// [Diagnostic]: hir::diagnostics::Diagnostic
+pub trait DiagnosticWithFix: Diagnostic {
+    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
+}
+
+impl DiagnosticWithFix for UnresolvedModule {
+    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
+        let root = sema.db.parse_or_expand(self.file)?;
+        let unresolved_module = self.decl.to_node(&root);
+        Some(Fix::new(
+            "Create module",
+            FileSystemEdit::CreateFile {
+                anchor: self.file.original_file(sema.db),
+                dst: self.candidate.clone(),
+            }
+            .into(),
+            unresolved_module.syntax().text_range(),
+        ))
+    }
+}
+
+impl DiagnosticWithFix for NoSuchField {
+    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
+        let root = sema.db.parse_or_expand(self.file)?;
+        missing_record_expr_field_fix(
+            &sema,
+            self.file.original_file(sema.db),
+            &self.field.to_node(&root),
+        )
+    }
+}
+
+impl DiagnosticWithFix for MissingFields {
+    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
+        // Note that although we could add a diagnostics to
+        // fill the missing tuple field, e.g :
+        // `struct A(usize);`
+        // `let a = A { 0: () }`
+        // but it is uncommon usage and it should not be encouraged.
+        if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
+            return None;
+        }
+
+        let root = sema.db.parse_or_expand(self.file)?;
+        let old_field_list = self.field_list_parent.to_node(&root).record_expr_field_list()?;
+        let mut new_field_list = old_field_list.clone();
+        for f in self.missed_fields.iter() {
+            let field =
+                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
+            new_field_list = new_field_list.append_field(&field);
+        }
+
+        let edit = {
+            let mut builder = TextEdit::builder();
+            algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
+                .into_text_edit(&mut builder);
+            builder.finish()
+        };
+        Some(Fix::new(
+            "Fill struct fields",
+            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(),
+            sema.original_range(&old_field_list.syntax()).range,
+        ))
+    }
+}
+
+impl DiagnosticWithFix for MissingOkInTailExpr {
+    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
+        let root = sema.db.parse_or_expand(self.file)?;
+        let tail_expr = self.expr.to_node(&root);
+        let tail_expr_range = tail_expr.syntax().text_range();
+        let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax()));
+        let source_change =
+            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
+        Some(Fix::new("Wrap with ok", source_change, tail_expr_range))
+    }
+}
+
+fn missing_record_expr_field_fix(
+    sema: &Semantics<RootDatabase>,
+    usage_file_id: FileId,
+    record_expr_field: &ast::RecordExprField,
+) -> Option<Fix> {
+    let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
+    let def_id = sema.resolve_variant(record_lit)?;
+    let module;
+    let def_file_id;
+    let record_fields = match VariantDef::from(def_id) {
+        VariantDef::Struct(s) => {
+            module = s.module(sema.db);
+            let source = s.source(sema.db);
+            def_file_id = source.file_id;
+            let fields = source.value.field_list()?;
+            record_field_list(fields)?
+        }
+        VariantDef::Union(u) => {
+            module = u.module(sema.db);
+            let source = u.source(sema.db);
+            def_file_id = source.file_id;
+            source.value.record_field_list()?
+        }
+        VariantDef::EnumVariant(e) => {
+            module = e.module(sema.db);
+            let source = e.source(sema.db);
+            def_file_id = source.file_id;
+            let fields = source.value.field_list()?;
+            record_field_list(fields)?
+        }
+    };
+    let def_file_id = def_file_id.original_file(sema.db);
+
+    let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
+    if new_field_type.is_unknown() {
+        return None;
+    }
+    let new_field = make::record_field(
+        record_expr_field.field_name()?,
+        make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
+    );
+
+    let last_field = record_fields.fields().last()?;
+    let last_field_syntax = last_field.syntax();
+    let indent = IndentLevel::from_node(last_field_syntax);
+
+    let mut new_field = new_field.to_string();
+    if usage_file_id != def_file_id {
+        new_field = format!("pub(crate) {}", new_field);
+    }
+    new_field = format!("\n{}{}", indent, new_field);
+
+    let needs_comma = !last_field_syntax.to_string().ends_with(',');
+    if needs_comma {
+        new_field = format!(",{}", new_field);
+    }
+
+    let source_change = SourceFileEdit {
+        file_id: def_file_id,
+        edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
+    };
+    return Some(Fix::new(
+        "Create field",
+        source_change.into(),
+        record_expr_field.syntax().text_range(),
+    ));
+
+    fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
+        match field_def_list {
+            ast::FieldList::RecordFieldList(it) => Some(it),
+            ast::FieldList::TupleFieldList(_) => None,
+        }
+    }
+}
index 2a73abba2788617ad160398ccc21c2dbae938ba5..f37119e28bddc4ed4f6128378025223367f8bc7c 100644 (file)
@@ -65,7 +65,7 @@ macro_rules! eprintln {
     completion::{
         CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
     },
-    diagnostics::{DiagnosticsConfig, Severity},
+    diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity},
     display::NavigationTarget,
     expand_macro::ExpandedMacro,
     file_structure::StructureNode,
@@ -99,35 +99,6 @@ macro_rules! eprintln {
 
 pub type Cancelable<T> = Result<T, Canceled>;
 
-#[derive(Debug)]
-pub struct Diagnostic {
-    pub name: Option<String>,
-    pub message: String,
-    pub range: TextRange,
-    pub severity: Severity,
-    pub fix: Option<Fix>,
-}
-
-#[derive(Debug)]
-pub struct Fix {
-    pub label: String,
-    pub source_change: SourceChange,
-    /// Allows to trigger the fix only when the caret is in the range given
-    pub fix_trigger_range: TextRange,
-}
-
-impl Fix {
-    pub fn new(
-        label: impl Into<String>,
-        source_change: SourceChange,
-        fix_trigger_range: TextRange,
-    ) -> Self {
-        let label = label.into();
-        assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.'));
-        Self { label, source_change, fix_trigger_range }
-    }
-}
-
 /// Info associated with a text range.
 #[derive(Debug)]
 pub struct RangeInfo<T> {