Repository: rust-analyzer/rust-analyzer
Pull request #9079 (2021-05-31 13:36:01)

Don't take the parent kind of trailing attributes in attr completion
bors r+
fixes https://github.com/rust-analyzer/rust-analyzer/issues/9076


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index ee04cdce8e..15ccf4146d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1375,9 +1375,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
 
 [[package]]
 name = "salsa"
-version = "0.17.0-pre.1"
+version = "0.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58038261ea8cd5a7730c4d8c97a22063d7c7eb1c2809e55c3c15f0a5903e5582"
+checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403"
 dependencies = [
  "crossbeam-utils",
  "indexmap",
@@ -1392,9 +1392,9 @@ dependencies = [
 
 [[package]]
 name = "salsa-macros"
-version = "0.17.0-pre.1"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e2fc060627fa5d44bffac98f6089b9497779e2deccc26687f60adc2638e32fb"
+checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2"
 dependencies = [
  "heck",
  "proc-macro2",
diff --git a/crates/base_db/Cargo.toml b/crates/base_db/Cargo.toml
index 69173ad1f3..1724d2f85a 100644
--- a/crates/base_db/Cargo.toml
+++ b/crates/base_db/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
 doctest = false
 
 [dependencies]
-salsa = "0.17.0-pre.1"
+salsa = "0.16.0"
 rustc-hash = "1.1.0"
 
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/base_db/src/cancellation.rs b/crates/base_db/src/cancellation.rs
new file mode 100644
index 0000000000..7420a1976f
--- /dev/null
+++ b/crates/base_db/src/cancellation.rs
@@ -0,0 +1,48 @@
+//! Utility types to support cancellation.
+//!
+//! In a typical IDE use-case, requests and modification happen concurrently, as
+//! in the following scenario:
+//!
+//!   * user types a character,
+//!   * a syntax highlighting process is started
+//!   * user types next character, while syntax highlighting *is still in
+//!     progress*.
+//!
+//! In this situation, we want to react to modification as quickly as possible.
+//! At the same time, in-progress results are not very interesting, because they
+//! are invalidated by the edit anyway. So, we first cancel all in-flight
+//! requests, and then apply modification knowing that it won't interfere with
+//! any background processing (this bit is handled by salsa, see the
+//! `BaseDatabase::check_canceled` method).
+
+/// An "error" signifying that the operation was canceled.
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct Canceled {
+    _private: (),
+}
+
+impl Canceled {
+    pub(crate) fn new() -> Canceled {
+        Canceled { _private: () }
+    }
+
+    pub fn throw() -> ! {
+        // We use resume and not panic here to avoid running the panic
+        // hook (that is, to avoid collecting and printing backtrace).
+        std::panic::resume_unwind(Box::new(Canceled::new()))
+    }
+}
+
+impl std::fmt::Display for Canceled {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        fmt.write_str("canceled")
+    }
+}
+
+impl std::fmt::Debug for Canceled {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "Canceled")
+    }
+}
+
+impl std::error::Error for Canceled {}
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 62bf2a4b2c..980a0ed985 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -1,4 +1,5 @@
 //! base_db defines basic database traits. The concrete DB is defined by ide.
+mod cancellation;
 mod input;
 mod change;
 pub mod fixture;
@@ -9,13 +10,14 @@ use rustc_hash::FxHashSet;
 use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
 
 pub use crate::{
+    cancellation::Canceled,
     change::Change,
     input::{
         CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
         ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
     },
 };
-pub use salsa::{self, Cancelled};
+pub use salsa;
 pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
 
 #[macro_export]
@@ -36,6 +38,45 @@ pub trait Upcast<T: ?Sized> {
     fn upcast(&self) -> &T;
 }
 
+pub trait CheckCanceled {
+    /// Aborts current query if there are pending changes.
+    ///
+    /// rust-analyzer needs to be able to answer semantic questions about the
+    /// code while the code is being modified. A common problem is that a
+    /// long-running query is being calculated when a new change arrives.
+    ///
+    /// We can't just apply the change immediately: this will cause the pending
+    /// query to see inconsistent state (it will observe an absence of
+    /// repeatable read). So what we do is we **cancel** all pending queries
+    /// before applying the change.
+    ///
+    /// We implement cancellation by panicking with a special value and catching
+    /// it on the API boundary. Salsa explicitly supports this use-case.
+    fn check_canceled(&self);
+
+    fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled>
+    where
+        Self: Sized + panic::RefUnwindSafe,
+        F: FnOnce(&Self) -> T + panic::UnwindSafe,
+    {
+        // Uncomment to debug missing cancellations.
+        // let _span = profile::heartbeat_span();
+        panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
+            Ok(canceled) => *canceled,
+            Err(payload) => panic::resume_unwind(payload),
+        })
+    }
+}
+
+impl<T: salsa::Database> CheckCanceled for T {
+    fn check_canceled(&self) {
+        // profile::heartbeat();
+        if self.salsa_runtime().is_current_revision_canceled() {
+            Canceled::throw()
+        }
+    }
+}
+
 #[derive(Clone, Copy, Debug)]
 pub struct FilePosition {
     pub file_id: FileId,
@@ -60,7 +101,7 @@ pub trait FileLoader {
 /// Database which stores all significant input facts: source code and project
 /// model. Everything else in rust-analyzer is derived from these queries.
 #[salsa::query_group(SourceDatabaseStorage)]
-pub trait SourceDatabase: FileLoader + std::fmt::Debug {
+pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
     // Parses the file into the syntax tree.
     #[salsa::invoke(parse_query)]
     fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 2cdbd172a5..22ec7c6aca 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -227,27 +227,3 @@ impl Diagnostic for MacroError {
         true
     }
 }
-
-#[derive(Debug)]
-pub struct UnimplementedBuiltinMacro {
-    pub file: HirFileId,
-    pub node: SyntaxNodePtr,
-}
-
-impl Diagnostic for UnimplementedBuiltinMacro {
-    fn code(&self) -> DiagnosticCode {
-        DiagnosticCode("unimplemented-builtin-macro")
-    }
-
-    fn message(&self) -> String {
-        "unimplemented built-in macro".to_string()
-    }
-
-    fn display_source(&self) -> InFile<SyntaxNodePtr> {
-        InFile::new(self.file, self.node.clone())
-    }
-
-    fn as_any(&self) -> &(dyn Any + Send + 'static) {
-        self
-    }
-}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d3ef29db4e..975ae48690 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -36,8 +36,8 @@ use std::{iter, sync::Arc};
 use arrayvec::ArrayVec;
 use base_db::{CrateDisplayName, CrateId, Edition, FileId};
 use diagnostics::{
-    InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
-    UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
+    InactiveCode, MacroError, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
+    UnresolvedModule, UnresolvedProcMacro,
 };
 use either::Either;
 use hir_def::{
@@ -565,14 +565,6 @@ impl Module {
                     };
                     sink.push(MacroError { file, node: ast, message: message.clone() });
                 }
-
-                DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
-                    let node = ast.to_node(db.upcast());
-                    // Must have a name, otherwise we wouldn't emit it.
-                    let name = node.name().expect("unimplemented builtin macro with no name");
-                    let ptr = SyntaxNodePtr::from(AstPtr::new(&name));
-                    sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr });
-                }
             }
         }
         for decl in self.declarations(db) {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c7f2c02e4c..8d3c43d082 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -361,7 +361,7 @@ impl<'db> SemanticsImpl<'db> {
         let sa = self.analyze(&parent);
 
         let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
-            self.db.unwind_if_cancelled();
+            self.db.check_canceled();
             let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
             let tt = macro_call.token_tree()?;
             if !tt.syntax().text_range().contains_range(token.value.text_range()) {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 7f9fdb3793..d9d6c91a85 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -351,7 +351,7 @@ impl DefCollector<'_> {
         let mut i = 0;
         'outer: loop {
             loop {
-                self.db.unwind_if_cancelled();
+                self.db.check_canceled();
                 loop {
                     if self.resolve_imports() == ReachedFixedPoint::Yes {
                         break;
@@ -836,7 +836,7 @@ impl DefCollector<'_> {
         vis: Visibility,
         import_type: ImportType,
     ) {
-        self.db.unwind_if_cancelled();
+        self.db.check_canceled();
         self.update_recursive(module_id, resolutions, vis, import_type, 0)
     }
 
@@ -1679,22 +1679,14 @@ impl ModCollector<'_, '_> {
                 None => &mac.name,
             };
             let krate = self.def_collector.def_map.krate;
-            match find_builtin_macro(name, krate, ast_id) {
-                Some(macro_id) => {
-                    self.def_collector.define_macro_rules(
-                        self.module_id,
-                        mac.name.clone(),
-                        macro_id,
-                        is_export,
-                    );
-                    return;
-                }
-                None => {
-                    self.def_collector
-                        .def_map
-                        .diagnostics
-                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
-                }
+            if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
+                self.def_collector.define_macro_rules(
+                    self.module_id,
+                    mac.name.clone(),
+                    macro_id,
+                    is_export,
+                );
+                return;
             }
         }
 
@@ -1723,23 +1715,15 @@ impl ModCollector<'_, '_> {
             let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
                 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
 
-            match macro_id {
-                Some(macro_id) => {
-                    self.def_collector.define_macro_def(
-                        self.module_id,
-                        mac.name.clone(),
-                        macro_id,
-                        &self.item_tree[mac.visibility],
-                    );
-                    return;
-                }
-                None => {
-                    self.def_collector
-                        .def_map
-                        .diagnostics
-                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
-                }
+            if let Some(macro_id) = macro_id {
+                self.def_collector.define_macro_def(
+                    self.module_id,
+                    mac.name.clone(),
+                    macro_id,
+                    &self.item_tree[mac.visibility],
+                );
             }
+            return;
         }
 
         // Case 2: normal `macro`
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs
index 95061f6015..57c36c3c6c 100644
--- a/crates/hir_def/src/nameres/diagnostics.rs
+++ b/crates/hir_def/src/nameres/diagnostics.rs
@@ -27,8 +27,6 @@ pub enum DefDiagnosticKind {
     UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
 
     MacroError { ast: MacroCallKind, message: String },
-
-    UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
 }
 
 #[derive(Debug, PartialEq, Eq)]
@@ -95,11 +93,4 @@ impl DefDiagnostic {
     ) -> Self {
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
     }
-
-    pub(super) fn unimplemented_builtin_macro(
-        container: LocalModuleId,
-        ast: AstId<ast::Macro>,
-    ) -> Self {
-        Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } }
-    }
 }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 41ef45326b..97507305c2 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -119,7 +119,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
-        self.db.unwind_if_cancelled();
+        self.db.check_canceled();
 
         let body = Arc::clone(&self.body); // avoid borrow checker problem
         let ty = match &body[tgt_expr] {
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index f589b314b8..294cb531c8 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -112,7 +112,7 @@ fn solve(
     let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
 
     let should_continue = || {
-        db.unwind_if_cancelled();
+        context.db.check_canceled();
         let remaining = fuel.get();
         fuel.set(remaining - 1);
         if remaining == 0 {
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index d5c954b8bb..6cf5810fa4 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -182,11 +182,6 @@ pub(crate) fn diagnostics(
             res.borrow_mut()
                 .push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
         })
-        .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
-            let display_range = sema.diagnostics_display_range(d.display_source()).range;
-            res.borrow_mut()
-                .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
-        })
         // Only collect experimental diagnostics when they're enabled.
         .filter(|diag| !(diag.is_experimental() && config.disable_experimental))
         .filter(|diag| !config.disabled.contains(diag.code().as_str()));
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 97c9e5d2b4..ff2a54117b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -58,7 +58,7 @@ use cfg::CfgOptions;
 
 use ide_db::base_db::{
     salsa::{self, ParallelDatabase},
-    Env, FileLoader, FileSet, SourceDatabase, VfsPath,
+    CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
 };
 use ide_db::{
     symbol_index::{self, FileSymbol},
@@ -98,7 +98,7 @@ pub use ide_completion::{
 };
 pub use ide_db::{
     base_db::{
-        Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
+        Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
         SourceRoot, SourceRootId,
     },
     call_info::CallInfo,
@@ -113,7 +113,7 @@ pub use ide_ssr::SsrError;
 pub use syntax::{TextRange, TextSize};
 pub use text_edit::{Indel, TextEdit};
 
-pub type Cancellable<T> = Result<T, Cancelled>;
+pub type Cancelable<T> = Result<T, Canceled>;
 
 /// Info associated with a text range.
 #[derive(Debug)]
@@ -227,11 +227,11 @@ impl Analysis {
     }
 
     /// Debug info about the current state of the analysis.
-    pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
+    pub fn status(&self, file_id: Option<FileId>) -> Cancelable<String> {
         self.with_db(|db| status::status(&*db, file_id))
     }
 
-    pub fn prime_caches<F>(&self, cb: F) -> Cancellable<()>
+    pub fn prime_caches<F>(&self, cb: F) -> Cancelable<()>
     where
         F: Fn(PrimeCachesProgress) + Sync + std::panic::UnwindSafe,
     {
@@ -239,35 +239,35 @@ impl Analysis {
     }
 
     /// Gets the text of the source file.
-    pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<String>> {
+    pub fn file_text(&self, file_id: FileId) -> Cancelable<Arc<String>> {
         self.with_db(|db| db.file_text(file_id))
     }
 
     /// Gets the syntax tree of the file.
-    pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
+    pub fn parse(&self, file_id: FileId) -> Cancelable<SourceFile> {
         self.with_db(|db| db.parse(file_id).tree())
     }
 
     /// Returns true if this file belongs to an immutable library.
-    pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
+    pub fn is_library_file(&self, file_id: FileId) -> Cancelable<bool> {
         use ide_db::base_db::SourceDatabaseExt;
         self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
     }
 
     /// Gets the file's `LineIndex`: data structure to convert between absolute
     /// offsets and line/column representation.
-    pub fn file_line_index(&self, file_id: FileId) -> Cancellable<Arc<LineIndex>> {
+    pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> {
         self.with_db(|db| db.line_index(file_id))
     }
 
     /// Selects the next syntactic nodes encompassing the range.
-    pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
+    pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> {
         self.with_db(|db| extend_selection::extend_selection(db, frange))
     }
 
     /// Returns position of the matching brace (all types of braces are
     /// supported).
-    pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
+    pub fn matching_brace(&self, position: FilePosition) -> Cancelable<Option<TextSize>> {
         self.with_db(|db| {
             let parse = db.parse(position.file_id);
             let file = parse.tree();
@@ -281,30 +281,30 @@ impl Analysis {
         &self,
         file_id: FileId,
         text_range: Option<TextRange>,
-    ) -> Cancellable<String> {
+    ) -> Cancelable<String> {
         self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range))
     }
 
-    pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> {
+    pub fn view_hir(&self, position: FilePosition) -> Cancelable<String> {
         self.with_db(|db| view_hir::view_hir(&db, position))
     }
 
-    pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {
+    pub fn view_item_tree(&self, file_id: FileId) -> Cancelable<String> {
         self.with_db(|db| view_item_tree::view_item_tree(&db, file_id))
     }
 
     /// Renders the crate graph to GraphViz "dot" syntax.
-    pub fn view_crate_graph(&self) -> Cancellable<Result<String, String>> {
+    pub fn view_crate_graph(&self) -> Cancelable<Result<String, String>> {
         self.with_db(|db| view_crate_graph::view_crate_graph(&db))
     }
 
-    pub fn expand_macro(&self, position: FilePosition) -> Cancellable<Option<ExpandedMacro>> {
+    pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
         self.with_db(|db| expand_macro::expand_macro(db, position))
     }
 
     /// Returns an edit to remove all newlines in the range, cleaning up minor
     /// stuff like trailing commas.
-    pub fn join_lines(&self, frange: FileRange) -> Cancellable<TextEdit> {
+    pub fn join_lines(&self, frange: FileRange) -> Cancelable<TextEdit> {
         self.with_db(|db| {
             let parse = db.parse(frange.file_id);
             join_lines::join_lines(&parse.tree(), frange.range)
@@ -314,7 +314,7 @@ impl Analysis {
     /// Returns an edit which should be applied when opening a new line, fixing
     /// up minor stuff like continuing the comment.
     /// The edit will be a snippet (with `$0`).
-    pub fn on_enter(&self, position: FilePosition) -> Cancellable<Option<TextEdit>> {
+    pub fn on_enter(&self, position: FilePosition) -> Cancelable<Option<TextEdit>> {
         self.with_db(|db| typing::on_enter(&db, position))
     }
 
@@ -326,7 +326,7 @@ impl Analysis {
         &self,
         position: FilePosition,
         char_typed: char,
-    ) -> Cancellable<Option<SourceChange>> {
+    ) -> Cancelable<Option<SourceChange>> {
         // Fast path to not even parse the file.
         if !typing::TRIGGER_CHARS.contains(char_typed) {
             return Ok(None);
@@ -336,7 +336,7 @@ impl Analysis {
 
     /// Returns a tree representation of symbols in the file. Useful to draw a
     /// file outline.
-    pub fn file_structure(&self, file_id: FileId) -> Cancellable<Vec<StructureNode>> {
+    pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> {
         self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
     }
 
@@ -345,17 +345,17 @@ impl Analysis {
         &self,
         file_id: FileId,
         config: &InlayHintsConfig,
-    ) -> Cancellable<Vec<InlayHint>> {
+    ) -> Cancelable<Vec<InlayHint>> {
         self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config))
     }
 
     /// Returns the set of folding ranges.
-    pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
+    pub fn folding_ranges(&self, file_id: FileId) -> Cancelable<Vec<Fold>> {
         self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree()))
     }
 
     /// Fuzzy searches for a symbol.
-    pub fn symbol_search(&self, query: Query) -> Cancellable<Vec<NavigationTarget>> {
+    pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> {
         self.with_db(|db| {
             symbol_index::world_symbols(db, query)
                 .into_iter()
@@ -368,7 +368,7 @@ impl Analysis {
     pub fn goto_definition(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
+    ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
         self.with_db(|db| goto_definition::goto_definition(db, position))
     }
 
@@ -376,7 +376,7 @@ impl Analysis {
     pub fn goto_implementation(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
+    ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
         self.with_db(|db| goto_implementation::goto_implementation(db, position))
     }
 
@@ -384,7 +384,7 @@ impl Analysis {
     pub fn goto_type_definition(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
+    ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
         self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
     }
 
@@ -393,12 +393,12 @@ impl Analysis {
         &self,
         position: FilePosition,
         search_scope: Option<SearchScope>,
-    ) -> Cancellable<Option<ReferenceSearchResult>> {
+    ) -> Cancelable<Option<ReferenceSearchResult>> {
         self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
     }
 
     /// Finds all methods and free functions for the file. Does not return tests!
-    pub fn find_all_methods(&self, file_id: FileId) -> Cancellable<Vec<FileRange>> {
+    pub fn find_all_methods(&self, file_id: FileId) -> Cancelable<Vec<FileRange>> {
         self.with_db(|db| fn_references::find_all_methods(db, file_id))
     }
 
@@ -408,7 +408,7 @@ impl Analysis {
         position: FilePosition,
         links_in_hover: bool,
         markdown: bool,
-    ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
+    ) -> Cancelable<Option<RangeInfo<HoverResult>>> {
         self.with_db(|db| hover::hover(db, position, links_in_hover, markdown))
     }
 
@@ -416,12 +416,12 @@ impl Analysis {
     pub fn external_docs(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Option<doc_links::DocumentationLink>> {
+    ) -> Cancelable<Option<doc_links::DocumentationLink>> {
         self.with_db(|db| doc_links::external_docs(db, &position))
     }
 
     /// Computes parameter information for the given call expression.
-    pub fn call_info(&self, position: FilePosition) -> Cancellable<Option<CallInfo>> {
+    pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
         self.with_db(|db| ide_db::call_info::call_info(db, position))
     }
 
@@ -429,42 +429,42 @@ impl Analysis {
     pub fn call_hierarchy(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
+    ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
         self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
     }
 
     /// Computes incoming calls for the given file position.
-    pub fn incoming_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
+    pub fn incoming_calls(&self, position: FilePosition) -> Cancelable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::incoming_calls(db, position))
     }
 
     /// Computes incoming calls for the given file position.
-    pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
+    pub fn outgoing_calls(&self, position: FilePosition) -> Cancelable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
     }
 
     /// Returns a `mod name;` declaration which created the current module.
-    pub fn parent_module(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
+    pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
         self.with_db(|db| parent_module::parent_module(db, position))
     }
 
     /// Returns crates this file belongs too.
-    pub fn crate_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
+    pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
         self.with_db(|db| parent_module::crate_for(db, file_id))
     }
 
     /// Returns the edition of the given crate.
-    pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable<Edition> {
+    pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> {
         self.with_db(|db| db.crate_graph()[crate_id].edition)
     }
 
     /// Returns the root file of the given crate.
-    pub fn crate_root(&self, crate_id: CrateId) -> Cancellable<FileId> {
+    pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
         self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
     }
 
     /// Returns the set of possible targets to run for the current file.
-    pub fn runnables(&self, file_id: FileId) -> Cancellable<Vec<Runnable>> {
+    pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
         self.with_db(|db| runnables::runnables(db, file_id))
     }
 
@@ -473,24 +473,24 @@ impl Analysis {
         &self,
         position: FilePosition,
         search_scope: Option<SearchScope>,
-    ) -> Cancellable<Vec<Runnable>> {
+    ) -> Cancelable<Vec<Runnable>> {
         self.with_db(|db| runnables::related_tests(db, position, search_scope))
     }
 
     /// Computes syntax highlighting for the given file
-    pub fn highlight(&self, file_id: FileId) -> Cancellable<Vec<HlRange>> {
+    pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HlRange>> {
         self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
     }
 
     /// Computes syntax highlighting for the given file range.
-    pub fn highlight_range(&self, frange: FileRange) -> Cancellable<Vec<HlRange>> {
+    pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HlRange>> {
         self.with_db(|db| {
             syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
         })
     }
 
     /// Computes syntax highlighting for the given file.
-    pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
+    pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancelable<String> {
         self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
     }
 
@@ -499,7 +499,7 @@ impl Analysis {
         &self,
         config: &CompletionConfig,
         position: FilePosition,
-    ) -> Cancellable<Option<Vec<CompletionItem>>> {
+    ) -> Cancelable<Option<Vec<CompletionItem>>> {
         self.with_db(|db| ide_completion::completions(db, config, position).map(Into::into))
     }
 
@@ -510,7 +510,7 @@ impl Analysis {
         position: FilePosition,
         full_import_path: &str,
         imported_name: String,
-    ) -> Cancellable<Vec<TextEdit>> {
+    ) -> Cancelable<Vec<TextEdit>> {
         Ok(self
             .with_db(|db| {
                 ide_completion::resolve_completion_edits(
@@ -533,7 +533,7 @@ impl Analysis {
         config: &AssistConfig,
         resolve: AssistResolveStrategy,
         frange: FileRange,
-    ) -> Cancellable<Vec<Assist>> {
+    ) -> Cancelable<Vec<Assist>> {
         self.with_db(|db| {
             let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
             let mut acc = Assist::get(db, config, resolve, frange);
@@ -548,7 +548,7 @@ impl Analysis {
         config: &DiagnosticsConfig,
         resolve: AssistResolveStrategy,
         file_id: FileId,
-    ) -> Cancellable<Vec<Diagnostic>> {
+    ) -> Cancelable<Vec<Diagnostic>> {
         self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id))
     }
 
@@ -559,7 +559,7 @@ impl Analysis {
         diagnostics_config: &DiagnosticsConfig,
         resolve: AssistResolveStrategy,
         frange: FileRange,
-    ) -> Cancellable<Vec<Assist>> {
+    ) -> Cancelable<Vec<Assist>> {
         let include_fixes = match &assist_config.allowed {
             Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
             None => true,
@@ -591,14 +591,14 @@ impl Analysis {
         &self,
         position: FilePosition,
         new_name: &str,
-    ) -> Cancellable<Result<SourceChange, RenameError>> {
+    ) -> Cancelable<Result<SourceChange, RenameError>> {
         self.with_db(|db| references::rename::rename(db, position, new_name))
     }
 
     pub fn prepare_rename(
         &self,
         position: FilePosition,
-    ) -> Cancellable<Result<RangeInfo<()>, RenameError>> {
+    ) -> Cancelable<Result<RangeInfo<()>, RenameError>> {
         self.with_db(|db| references::rename::prepare_rename(db, position))
     }
 
@@ -606,7 +606,7 @@ impl Analysis {
         &self,
         file_id: FileId,
         new_name_stem: &str,
-    ) -> Cancellable<Option<SourceChange>> {
+    ) -> Cancelable<Option<SourceChange>> {
         self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem))
     }
 
@@ -616,7 +616,7 @@ impl Analysis {
         parse_only: bool,
         resolve_context: FilePosition,
         selections: Vec<FileRange>,
-    ) -> Cancellable<Result<SourceChange, SsrError>> {
+    ) -> Cancelable<Result<SourceChange, SsrError>> {
         self.with_db(|db| {
             let rule: ide_ssr::SsrRule = query.parse()?;
             let mut match_finder =
@@ -631,11 +631,11 @@ impl Analysis {
         &self,
         file_id: FileId,
         config: AnnotationConfig,
-    ) -> Cancellable<Vec<Annotation>> {
+    ) -> Cancelable<Vec<Annotation>> {
         self.with_db(|db| annotations::annotations(db, file_id, config))
     }
 
-    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
+    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancelable<Annotation> {
         self.with_db(|db| annotations::resolve_annotation(db, annotation))
     }
 
@@ -643,28 +643,16 @@ impl Analysis {
         &self,
         range: FileRange,
         direction: Direction,
-    ) -> Cancellable<Option<TextEdit>> {
+    ) -> Cancelable<Option<TextEdit>> {
         self.with_db(|db| move_item::move_item(db, range, direction))
     }
 
-    /// Performs an operation on the database that may be canceled.
-    ///
-    /// rust-analyzer needs to be able to answer semantic questions about the
-    /// code while the code is being modified. A common problem is that a
-    /// long-running query is being calculated when a new change arrives.
-    ///
-    /// We can't just apply the change immediately: this will cause the pending
-    /// query to see inconsistent state (it will observe an absence of
-    /// repeatable read). So what we do is we **cancel** all pending queries
-    /// before applying the change.
-    ///
-    /// Salsa implements cancelation by unwinding with a special value and
-    /// catching it on the API boundary.
-    fn with_db<F, T>(&self, f: F) -> Cancellable<T>
+    /// Performs an operation on that may be Canceled.
+    fn with_db<F, T>(&self, f: F) -> Cancelable<T>
     where
         F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
     {
-        Cancelled::catch(|| f(&self.db))
+        self.db.catch_canceled(f)
     }
 }
 
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index ffdcdc930a..151bf37839 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -69,25 +69,18 @@ impl Completions {
         items.into_iter().for_each(|item| self.add(item.into()))
     }
 
-    pub(crate) fn add_field(
-        &mut self,
-        ctx: &CompletionContext,
-        receiver: Option<hir::Name>,
-        field: hir::Field,
-        ty: &hir::Type,
-    ) {
-        let item = render_field(RenderContext::new(ctx), receiver, field, ty);
+    pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &hir::Type) {
+        let item = render_field(RenderContext::new(ctx), field, ty);
         self.add(item);
     }
 
     pub(crate) fn add_tuple_field(
         &mut self,
         ctx: &CompletionContext,
-        receiver: Option<hir::Name>,
         field: usize,
         ty: &hir::Type,
     ) {
-        let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
+        let item = render_tuple_field(RenderContext::new(ctx), field, ty);
         self.add(item);
     }
 
@@ -139,11 +132,9 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext,
         func: hir::Function,
-        receiver: Option<hir::Name>,
         local_name: Option<hir::Name>,
     ) {
-        if let Some(item) = render_method(RenderContext::new(ctx), None, receiver, local_name, func)
-        {
+        if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) {
             self.add(item)
         }
     }
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 76d926157c..c48bb9e661 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -5,7 +5,7 @@
 
 use once_cell::sync::Lazy;
 use rustc_hash::{FxHashMap, FxHashSet};
-use syntax::{ast, AstNode, NodeOrToken, SyntaxKind, T};
+use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T};
 
 use crate::{
     context::CompletionContext,
@@ -37,7 +37,13 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
 }
 
 fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
-    let attribute_annotated_item_kind = attribute.syntax().parent().map(|it| it.kind());
+    let is_inner = attribute.kind() == ast::AttrKind::Inner;
+    let attribute_annotated_item_kind =
+        attribute.syntax().parent().map(|it| it.kind()).filter(|_| {
+            is_inner
+            // If we got nothing coming after the attribute it could be anything so filter it the kind out
+                || non_trivia_sibling(attribute.syntax().clone().into(), Direction::Next).is_some()
+        });
     let attributes = attribute_annotated_item_kind.and_then(|kind| {
         if ast::Expr::can_cast(kind) {
             Some(EXPR_ATTRIBUTES)
@@ -45,7 +51,6 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
             KIND_TO_ATTRIBUTES.get(&kind).copied()
         }
     });
-    let is_inner = attribute.kind() == ast::AttrKind::Inner;
 
     let add_completion = |attr_completion: &AttrCompletion| {
         let mut item = CompletionItem::new(
@@ -781,4 +786,49 @@ mod tests {
             "#]],
         );
     }
+
+    #[test]
+    fn complete_attribute_in_source_file_end() {
+        check(
+            r#"#[$0]"#,
+            expect![[r#"
+                at allow(…)
+                at automatically_derived
+                at cfg(…)
+                at cfg_attr(…)
+                at cold
+                at deny(…)
+                at deprecated
+                at derive(…)
+                at doc = "…"
+                at doc(alias = "…")
+                at doc(hidden)
+                at export_name = "…"
+                at forbid(…)
+                at global_allocator
+                at ignore = "…"
+                at inline
+                at link
+                at link_name = "…"
+                at link_section = "…"
+                at macro_export
+                at macro_use
+                at must_use
+                at no_mangle
+                at non_exhaustive
+                at panic_handler
+                at path = "…"
+                at proc_macro
+                at proc_macro_attribute
+                at proc_macro_derive(…)
+                at repr(…)
+                at should_panic
+                at target_feature = "…"
+                at test
+                at track_caller
+                at used
+                at warn(…)
+            "#]],
+        );
+    }
 }
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 302c9ccbd3..fd97387437 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -1,7 +1,6 @@
 //! Completes references after dot (fields and method calls).
 
-use either::Either;
-use hir::{HasVisibility, ScopeDef};
+use hir::{HasVisibility, Type};
 use rustc_hash::FxHashSet;
 
 use crate::{context::CompletionContext, Completions};
@@ -10,7 +9,7 @@ use crate::{context::CompletionContext, Completions};
 pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
     let dot_receiver = match &ctx.dot_receiver {
         Some(expr) => expr,
-        _ => return complete_undotted_self(acc, ctx),
+        _ => return,
     };
 
     let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
@@ -21,43 +20,12 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
     if ctx.is_call {
         cov_mark::hit!(test_no_struct_field_completion_for_method_call);
     } else {
-        complete_fields(ctx, &receiver_ty, |field, ty| match field {
-            Either::Left(field) => acc.add_field(ctx, None, field, &ty),
-            Either::Right(tuple_idx) => acc.add_tuple_field(ctx, None, tuple_idx, &ty),
-        });
+        complete_fields(acc, ctx, &receiver_ty);
     }
-    complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None));
-}
-
-fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) {
-    if !ctx.is_trivial_path || !ctx.config.enable_self_on_the_fly {
-        return;
-    }
-    ctx.scope.process_all_names(&mut |name, def| {
-        if let ScopeDef::Local(local) = &def {
-            if local.is_self(ctx.db) {
-                let ty = local.ty(ctx.db);
-                complete_fields(ctx, &ty, |field, ty| match field {
-                    either::Either::Left(field) => {
-                        acc.add_field(ctx, Some(name.clone()), field, &ty)
-                    }
-                    either::Either::Right(tuple_idx) => {
-                        acc.add_tuple_field(ctx, Some(name.clone()), tuple_idx, &ty)
-                    }
-                });
-                complete_methods(ctx, &ty, |func| {
-                    acc.add_method(ctx, func, Some(name.clone()), None)
-                });
-            }
-        }
-    });
+    complete_methods(acc, ctx, &receiver_ty);
 }
 
-fn complete_fields(
-    ctx: &CompletionContext,
-    receiver: &hir::Type,
-    mut f: impl FnMut(Either<hir::Field, usize>, hir::Type),
-) {
+fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
     for receiver in receiver.autoderef(ctx.db) {
         for (field, ty) in receiver.fields(ctx.db) {
             if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
@@ -65,20 +33,16 @@ fn complete_fields(
                 // field is editable, we should show the completion
                 continue;
             }
-            f(Either::Left(field), ty);
+            acc.add_field(ctx, field, &ty);
         }
         for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
             // FIXME: Handle visibility
-            f(Either::Right(i), ty);
+            acc.add_tuple_field(ctx, i, &ty);
         }
     }
 }
 
-fn complete_methods(
-    ctx: &CompletionContext,
-    receiver: &hir::Type,
-    mut f: impl FnMut(hir::Function),
-) {
+fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
     if let Some(krate) = ctx.krate {
         let mut seen_methods = FxHashSet::default();
         let traits_in_scope = ctx.scope.traits_in_scope();
@@ -87,7 +51,7 @@ fn complete_methods(
                 && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
                 && seen_methods.insert(func.name(ctx.db))
             {
-                f(func);
+                acc.add_method(ctx, func, None);
             }
             None::<()>
         });
@@ -520,34 +484,4 @@ impl S {
             "#]],
         );
     }
-
-    #[test]
-    fn completes_bare_fields_and_methods_in_methods() {
-        check(
-            r#"
-struct Foo { field: i32 }
-
-impl Foo { fn foo(&self) { $0 } }"#,
-            expect![[r#"
-                lc self       &Foo
-                sp Self
-                st Foo
-                fd self.field i32
-                me self.foo() fn(&self)
-            "#]],
-        );
-        check(
-            r#"
-struct Foo(i32);
-
-impl Foo { fn foo(&mut self) { $0 } }"#,
-            expect![[r#"
-                lc self       &mut Foo
-                sp Self
-                st Foo
-                fd self.0     i32
-                me self.foo() fn(&mut self)
-            "#]],
-        );
-    }
 }
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 0ac47cdbe7..227c08d010 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -39,7 +39,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
     };
 
     for (field, ty) in missing_fields {
-        acc.add_field(ctx, None, field, &ty);
+        acc.add_field(ctx, field, &ty);
     }
 
     Some(())
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 20188a7ddc..9db8516d05 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -11,7 +11,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
     if ctx.is_path_disallowed() || ctx.expects_item() {
         return;
     }
-
     if ctx.expects_assoc_item() {
         ctx.scope.process_all_names(&mut |name, def| {
             if let ScopeDef::MacroDef(macro_def) = def {
@@ -33,7 +32,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
         });
         return;
     }
-
     if let Some(hir::Adt::Enum(e)) =
         ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
     {
diff --git a/crates/ide_completion/src/config.rs b/crates/ide_completion/src/config.rs
index c300ce887b..d70ed6c1cd 100644
--- a/crates/ide_completion/src/config.rs
+++ b/crates/ide_completion/src/config.rs
@@ -10,7 +10,6 @@ use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
 pub struct CompletionConfig {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
-    pub enable_self_on_the_fly: bool,
     pub add_call_parenthesis: bool,
     pub add_call_argument_snippets: bool,
     pub snippet_cap: Option<SnippetCap>,
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index a49a607112..425dd0247c 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -25,20 +25,18 @@ use crate::{
 
 pub(crate) fn render_field<'a>(
     ctx: RenderContext<'a>,
-    receiver: Option<hir::Name>,
     field: hir::Field,
     ty: &hir::Type,
 ) -> CompletionItem {
-    Render::new(ctx).render_field(receiver, field, ty)
+    Render::new(ctx).render_field(field, ty)
 }
 
 pub(crate) fn render_tuple_field<'a>(
     ctx: RenderContext<'a>,
-    receiver: Option<hir::Name>,
     field: usize,
     ty: &hir::Type,
 ) -> CompletionItem {
-    Render::new(ctx).render_tuple_field(receiver, field, ty)
+    Render::new(ctx).render_tuple_field(field, ty)
 }
 
 pub(crate) fn render_resolution<'a>(
@@ -128,19 +126,11 @@ impl<'a> Render<'a> {
         Render { ctx }
     }
 
-    fn render_field(
-        &self,
-        receiver: Option<hir::Name>,
-        field: hir::Field,
-        ty: &hir::Type,
-    ) -> CompletionItem {
+    fn render_field(&self, field: hir::Field, ty: &hir::Type) -> CompletionItem {
         let is_deprecated = self.ctx.is_deprecated(field);
         let name = field.name(self.ctx.db()).to_string();
-        let mut item = CompletionItem::new(
-            CompletionKind::Reference,
-            self.ctx.source_range(),
-            receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
-        );
+        let mut item =
+            CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name.clone());
         item.kind(SymbolKind::Field)
             .detail(ty.display(self.ctx.db()).to_string())
             .set_documentation(field.docs(self.ctx.db()))
@@ -161,17 +151,11 @@ impl<'a> Render<'a> {
         item.build()
     }
 
-    fn render_tuple_field(
-        &self,
-        receiver: Option<hir::Name>,
-        field: usize,
-        ty: &hir::Type,
-    ) -> CompletionItem {
+    fn render_tuple_field(&self, field: usize, ty: &hir::Type) -> CompletionItem {
         let mut item = CompletionItem::new(
             CompletionKind::Reference,
             self.ctx.source_range(),
-            receiver
-                .map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
+            field.to_string(),
         );
 
         item.kind(SymbolKind::Field).detail(ty.display(self.ctx.db()).to_string());
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 3ec77ca0f4..63bd669260 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -20,25 +20,23 @@ pub(crate) fn render_fn<'a>(
     fn_: hir::Function,
 ) -> Option<CompletionItem> {
     let _p = profile::span("render_fn");
-    Some(FunctionRender::new(ctx, None, local_name, fn_, false)?.render(import_to_add))
+    Some(FunctionRender::new(ctx, local_name, fn_, false)?.render(import_to_add))
 }
 
 pub(crate) fn render_method<'a>(
     ctx: RenderContext<'a>,
     import_to_add: Option<ImportEdit>,
-    receiver: Option<hir::Name>,
     local_name: Option<hir::Name>,
     fn_: hir::Function,
 ) -> Option<CompletionItem> {
     let _p = profile::span("render_method");
-    Some(FunctionRender::new(ctx, receiver, local_name, fn_, true)?.render(import_to_add))
+    Some(FunctionRender::new(ctx, local_name, fn_, true)?.render(import_to_add))
 }
 
 #[derive(Debug)]
 struct FunctionRender<'a> {
     ctx: RenderContext<'a>,
     name: String,
-    receiver: Option<hir::Name>,
     func: hir::Function,
     ast_node: Fn,
     is_method: bool,
@@ -47,7 +45,6 @@ struct FunctionRender<'a> {
 impl<'a> FunctionRender<'a> {
     fn new(
         ctx: RenderContext<'a>,
-        receiver: Option<hir::Name>,
         local_name: Option<hir::Name>,
         fn_: hir::Function,
         is_method: bool,
@@ -55,14 +52,11 @@ impl<'a> FunctionRender<'a> {
         let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string();
         let ast_node = fn_.source(ctx.db())?.value;
 
-        Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
+        Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method })
     }
 
-    fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem {
+    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
         let params = self.params();
-        if let Some(receiver) = &self.receiver {
-            self.name = format!("{}.{}", receiver, &self.name)
-        }
         let mut item = CompletionItem::new(
             CompletionKind::Reference,
             self.ctx.source_range(),
@@ -154,7 +148,7 @@ impl<'a> FunctionRender<'a> {
         };
 
         let mut params_pats = Vec::new();
-        let params_ty = if self.ctx.completion.dot_receiver.is_some() || self.receiver.is_some() {
+        let params_ty = if self.ctx.completion.dot_receiver.is_some() {
             self.func.method_params(self.ctx.db()).unwrap_or_default()
         } else {
             if let Some(s) = ast_params.self_param() {
@@ -259,26 +253,6 @@ impl S {
 fn bar(s: &S) {
     s.foo(${1:x})$0
 }
-"#,
-        );
-
-        check_edit(
-            "self.foo",
-            r#"
-struct S {}
-impl S {
-    fn foo(&self, x: i32) {
-        $0
-    }
-}
-"#,
-            r#"
-struct S {}
-impl S {
-    fn foo(&self, x: i32) {
-        self.foo(${1:x})$0
-    }
-}
 "#,
         );
     }
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 1f900aef4b..88ee4a87d5 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -19,7 +19,8 @@ use std::{fmt, sync::Arc};
 
 use base_db::{
     salsa::{self, Durability},
-    AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
+    AnchoredPath, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate,
+    SourceDatabase, Upcast,
 };
 use hir::db::{AstDatabase, DefDatabase, HirDatabase};
 use rustc_hash::FxHashSet;
@@ -79,7 +80,20 @@ impl FileLoader for RootDatabase {
     }
 }
 
-impl salsa::Database for RootDatabase {}
+impl salsa::Database for RootDatabase {
+    fn on_propagated_panic(&self) -> ! {
+        Canceled::throw()
+    }
+    fn salsa_event(&self, event: salsa::Event) {
+        match event.kind {
+            salsa::EventKind::DidValidateMemoizedValue { .. }
+            | salsa::EventKind::WillExecute { .. } => {
+                self.check_canceled();
+            }
+            _ => (),
+        }
+    }
+}
 
 impl Default for RootDatabase {
     fn default() -> RootDatabase {
@@ -112,7 +126,7 @@ impl salsa::ParallelDatabase for RootDatabase {
 }
 
 #[salsa::query_group(LineIndexDatabaseStorage)]
-pub trait LineIndexDatabase: base_db::SourceDatabase {
+pub trait LineIndexDatabase: base_db::SourceDatabase + CheckCanceled {
     fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
 }
 
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 5c372a7e5e..0f5c4abc4b 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -127,7 +127,7 @@ fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, Symb
 }
 
 fn file_symbols(db: &dyn SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
-    db.unwind_if_cancelled();
+    db.check_canceled();
     let parse = db.parse(file_id);
 
     let symbols = source_file_to_file_symbols(&parse.tree(), file_id);
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index ae78fd4f61..a67b0bb257 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -100,9 +100,6 @@ config_data! {
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = "true",
-        /// Toggles the additional completions that automatically show method calls and field accesses
-        /// with `self` prefixed to them when inside a method.
-        completion_autoself_enable: bool       = "true",
 
         /// Whether to show native rust-analyzer diagnostics.
         diagnostics_enable: bool                = "true",
@@ -669,7 +666,6 @@ impl Config {
             enable_postfix_completions: self.data.completion_postfix_enable,
             enable_imports_on_the_fly: self.data.completion_autoimport_enable
                 && completion_item_edit_resolve(&self.caps),
-            enable_self_on_the_fly: self.data.completion_autoself_enable,
             add_call_parenthesis: self.data.completion_addCallParenthesis,
             add_call_argument_snippets: self.data.completion_addCallArgumentSnippets,
             insert_use: self.insert_use_config(),
diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs
index 2011a41322..baf2199d94 100644
--- a/crates/rust-analyzer/src/dispatch.rs
+++ b/crates/rust-analyzer/src/dispatch.rs
@@ -5,7 +5,7 @@ use serde::{de::DeserializeOwned, Serialize};
 
 use crate::{
     global_state::{GlobalState, GlobalStateSnapshot},
-    lsp_utils::is_cancelled,
+    lsp_utils::is_canceled,
     main_loop::Task,
     LspError, Result,
 };
@@ -132,7 +132,7 @@ where
         Err(e) => match e.downcast::<LspError>() {
             Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
             Err(e) => {
-                if is_cancelled(&*e) {
+                if is_canceled(&*e) {
                     lsp_server::Response::new_err(
                         id,
                         lsp_server::ErrorCode::ContentModified as i32,
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index ea9dbf7fcd..6a36d29d4d 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant};
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
-use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
+use ide::{Analysis, AnalysisHost, Cancelable, Change, FileId};
 use ide_db::base_db::{CrateId, VfsPath};
 use lsp_types::{SemanticTokens, Url};
 use parking_lot::{Mutex, RwLock};
@@ -280,7 +280,7 @@ impl GlobalStateSnapshot {
         file_id_to_url(&self.vfs.read().0, id)
     }
 
-    pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
+    pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancelable<LineIndex> {
         let endings = self.vfs.read().1[&file_id];
         let index = self.analysis.file_line_index(file_id)?;
         let res = LineIndex { index, endings, encoding: self.config.offset_encoding() };
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index ec36a5f5c0..781073fe5b 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -132,7 +132,6 @@ fn integrated_completion_benchmark() {
         let config = CompletionConfig {
             enable_postfix_completions: true,
             enable_imports_on_the_fly: true,
-            enable_self_on_the_fly: true,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
@@ -167,7 +166,6 @@ fn integrated_completion_benchmark() {
         let config = CompletionConfig {
             enable_postfix_completions: true,
             enable_imports_on_the_fly: true,
-            enable_self_on_the_fly: true,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 8000b5490f..73c4193e88 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,7 +1,7 @@
 //! Utilities for LSP-related boilerplate code.
 use std::{error::Error, ops::Range, sync::Arc};
 
-use ide_db::base_db::Cancelled;
+use ide_db::base_db::Canceled;
 use lsp_server::Notification;
 
 use crate::{
@@ -10,8 +10,8 @@ use crate::{
     line_index::{LineEndings, LineIndex, OffsetEncoding},
 };
 
-pub(crate) fn is_cancelled(e: &(dyn Error + 'static)) -> bool {
-    e.downcast_ref::<Cancelled>().is_some()
+pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool {
+    e.downcast_ref::<Canceled>().is_some()
 }
 
 pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 31d8ea9e7f..008758ea0d 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -22,7 +22,7 @@ use crate::{
     from_proto,
     global_state::{file_id_to_url, url_to_file_id, GlobalState},
     handlers, lsp_ext,
-    lsp_utils::{apply_document_changes, is_cancelled, notification_is, Progress},
+    lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
     reload::{BuildDataProgress, ProjectWorkspaceProgress},
     Result,
 };
@@ -752,7 +752,7 @@ impl GlobalState {
                     .filter_map(|file_id| {
                         handlers::publish_diagnostics(&snapshot, file_id)
                             .map_err(|err| {
-                                if !is_cancelled(&*err) {
+                                if !is_canceled(&*err) {
                                     log::error!("failed to compute diagnostics: {:?}", err);
                                 }
                                 ()
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 7428a3043b..f5c8535a29 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -6,7 +6,7 @@ use std::{
 };
 
 use ide::{
-    Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancellable, CompletionItem,
+    Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancelable, CompletionItem,
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
     InlayKind, InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable,
@@ -727,7 +727,7 @@ pub(crate) fn snippet_text_document_edit(
 pub(crate) fn snippet_text_document_ops(
     snap: &GlobalStateSnapshot,
     file_system_edit: FileSystemEdit,
-) -> Cancellable<Vec<lsp_ext::SnippetDocumentChangeOperation>> {
+) -> Cancelable<Vec<lsp_ext::SnippetDocumentChangeOperation>> {
     let mut ops = Vec::new();
     match file_system_edit {
         FileSystemEdit::CreateFile { dst, initial_contents } => {
@@ -757,7 +757,7 @@ pub(crate) fn snippet_text_document_ops(
             let new_uri = snap.anchored_path(&dst);
             let mut rename_file =
                 lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None };
-            if snap.analysis.is_library_file(src).ok() == Some(true)
+            if snap.analysis.is_library_file(src) == Ok(true)
                 && snap.config.change_annotation_support()
             {
                 rename_file.annotation_id = Some(outside_workspace_annotation_id())
@@ -1178,7 +1178,6 @@ mod tests {
                 &ide::CompletionConfig {
                     enable_postfix_completions: true,
                     enable_imports_on_the_fly: true,
-                    enable_self_on_the_fly: true,
                     add_call_parenthesis: true,
                     add_call_argument_snippets: true,
                     snippet_cap: SnippetCap::new(true),
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 2624069a5c..39edf9e19c 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -447,8 +447,3 @@ This is cheap enough to enable in production.
 
 Similarly, we save live object counting (`RA_COUNT=1`).
 It is not cheap enough to enable in prod, and this is a bug which should be fixed.
-
-### Configurability
-
-rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet.
-There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience.
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index dbd9a3503b..4a5782a57e 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -136,12 +136,6 @@ Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 Toggles the additional completions that automatically add imports when completed.
 Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 --
-[[rust-analyzer.completion.autoself.enable]]rust-analyzer.completion.autoself.enable (default: `true`)::
-+
---
-Toggles the additional completions that automatically show method calls and field accesses
-with `self` prefixed to them when inside a method.
---
 [[rust-analyzer.diagnostics.enable]]rust-analyzer.diagnostics.enable (default: `true`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 42a06e1374..5b80cc1f9d 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -572,11 +572,6 @@
                     "default": true,
                     "type": "boolean"
                 },
-                "rust-analyzer.completion.autoself.enable": {
-                    "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.",
-                    "default": true,
-                    "type": "boolean"
-                },
                 "rust-analyzer.diagnostics.enable": {
                     "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
                     "default": true,


Test patch:
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index e840fe5e80..a9c1e13e2f 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -298,13 +298,6 @@ impl TestDB {
                     DefDiagnosticKind::MacroError { ast, message } => {
                         (ast.to_node(self.upcast()), message.as_str())
                     }
-                    DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
-                        let node = ast.to_node(self.upcast());
-                        (
-                            InFile::new(ast.file_id, node.syntax().clone()),
-                            "UnimplementedBuiltinMacro",
-                        )
-                    }
                 };
 
                 let frange = node.as_ref().original_file_range(self);
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index b0a4b2026b..93c7c872cc 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -19,7 +19,6 @@ use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
 pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_postfix_completions: true,
     enable_imports_on_the_fly: true,
-    enable_self_on_the_fly: true,
     add_call_parenthesis: true,
     add_call_argument_snippets: true,
     snippet_cap: SnippetCap::new(true),