Repository: rust-lang/rust-analyzer
Pull request #12108 (2022-04-28 13:18:26)

minor: Record snippet config errors


Patch:
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 08e239804c..bc43fb15ee 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -67,9 +67,8 @@ pub struct UnresolvedImport {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct UnresolvedMacroCall {
-    pub macro_call: InFile<SyntaxNodePtr>,
+    pub macro_call: InFile<AstPtr<ast::MacroCall>>,
     pub path: ModPath,
-    pub is_bang: bool,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2d73168727..382d1f9a54 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -701,9 +701,8 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
             let node = ast.to_node(db.upcast());
             acc.push(
                 UnresolvedMacroCall {
-                    macro_call: InFile::new(node.file_id, SyntaxNodePtr::new(&node.value)),
+                    macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
                     path: path.clone(),
-                    is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
                 }
                 .into(),
             );
@@ -1171,12 +1170,7 @@ impl DefWithBody {
                     .into(),
                 ),
                 BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
-                    UnresolvedMacroCall {
-                        macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
-                        path: path.clone(),
-                        is_bang: true,
-                    }
-                    .into(),
+                    UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(),
                 ),
             }
         }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 11d3f48b94..81054f83b0 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -813,15 +813,12 @@ impl Attr {
         let paths = args
             .token_trees
             .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
-            .filter_map(|tts| {
-                if tts.is_empty() {
-                    return None;
-                }
+            .map(|tts| {
                 let segments = tts.iter().filter_map(|tt| match tt {
                     tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
                     _ => None,
                 });
-                Some(ModPath::from_segments(PathKind::Plain, segments))
+                ModPath::from_segments(PathKind::Plain, segments)
             });
 
         Some(paths)
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index a9705cf2dc..15e93f729a 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1359,24 +1359,13 @@ impl DefCollector<'_> {
                     if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
                         self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                             directive.module_id,
-                            MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
+                            ast_id.ast_id,
                             path,
                         ));
                     }
                 }
-                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
-                    self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
-                        directive.module_id,
-                        MacroCallKind::Derive {
-                            ast_id: ast_id.ast_id,
-                            derive_attr_index: derive_attr.ast_index,
-                            derive_index: *derive_pos as u32,
-                        },
-                        ast_id.path.clone(),
-                    ));
-                }
-                MacroDirectiveKind::Attr { .. } => {
-                    // FIXME: these should get diagnosed by `reseed_with_unresolved_attribute`
+                MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => {
+                    // FIXME: we might want to diagnose this too
                 }
             }
         }
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs
index dd3ff92cb3..ab7a368268 100644
--- a/crates/hir_def/src/nameres/diagnostics.rs
+++ b/crates/hir_def/src/nameres/diagnostics.rs
@@ -25,7 +25,7 @@ pub enum DefDiagnosticKind {
 
     UnresolvedProcMacro { ast: MacroCallKind },
 
-    UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
+    UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
 
     MacroError { ast: MacroCallKind, message: String },
 
@@ -95,7 +95,7 @@ impl DefDiagnostic {
 
     pub(super) fn unresolved_macro_call(
         container: LocalModuleId,
-        ast: MacroCallKind,
+        ast: AstId<ast::MacroCall>,
         path: ModPath,
     ) -> Self {
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index fa36241c8c..f78e70f7a3 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -36,13 +36,13 @@ pub enum LifetimeElisionHints {
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum InlayKind {
-    ChainingHint,
+    ImplicitReborrow,
+    TypeHint,
+    ParameterHint,
     ClosureReturnTypeHint,
+    ChainingHint,
     GenericParamListHint,
-    ImplicitReborrow,
     LifetimeHint,
-    ParameterHint,
-    TypeHint,
 }
 
 #[derive(Debug)]
@@ -110,11 +110,11 @@ fn hints(
     config: &InlayHintsConfig,
     node: SyntaxNode,
 ) {
-    let famous_defs = match sema.scope(&node) {
-        Some(it) => FamousDefs(sema, it.krate()),
+    let krate = match sema.scope(&node) {
+        Some(it) => it.krate(),
         None => return,
     };
-
+    let famous_defs = FamousDefs(sema, krate);
     if let Some(expr) = ast::Expr::cast(node.clone()) {
         chaining_hints(hints, sema, &famous_defs, config, &expr);
         match expr {
@@ -1637,7 +1637,10 @@ fn main() {
     fn skip_constructor_and_enum_type_hints() {
         check_with_config(
             InlayHintsConfig {
+                render_colons: true,
                 type_hints: true,
+                parameter_hints: true,
+                chaining_hints: true,
                 hide_named_constructor_hints: true,
                 ..DISABLED_CONFIG
             },
@@ -2144,7 +2147,7 @@ impl () {
     #[test]
     fn hints_implicit_reborrow() {
         check_with_config(
-            InlayHintsConfig { reborrow_hints: true, parameter_hints: true, ..DISABLED_CONFIG },
+            InlayHintsConfig { reborrow_hints: true, ..DISABLED_CONFIG },
             r#"
 fn __() {
     let unique = &mut ();
@@ -2152,15 +2155,12 @@ fn __() {
     let foo: &mut _ = unique;
                     //^^^^^^ &mut *
     ref_mut_id(unique);
-             //^^^^^^ mut_ref
              //^^^^^^ &mut *
     let shared = ref_id(unique);
-                      //^^^^^^ shared_ref
                       //^^^^^^ &*
     let mov = shared;
     let r_mov: &_ = shared;
     ref_id(shared);
-         //^^^^^^ shared_ref
 
     identity(unique);
     identity(shared);
@@ -2168,12 +2168,12 @@ fn __() {
 fn identity<T>(t: T) -> T {
     t
 }
-fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
-    mut_ref
-  //^^^^^^^ &mut *
+fn ref_mut_id(x: &mut ()) -> &mut () {
+    x
+  //^ &mut *
 }
-fn ref_id(shared_ref: &()) -> &() {
-    shared_ref
+fn ref_id(x: &()) -> &() {
+    x
 }
 "#,
         );
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 8c2219860b..2c21bbc165 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -435,8 +435,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
                             ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
                         );
                     }
-                    format_to!(path, "::{}", def_name);
-                    return Some(path);
+                    return Some(format!(r#""{}::{}""#, path, def_name));
                 }
             }
         }
@@ -978,7 +977,7 @@ impl Data {
                         },
                         kind: DocTest {
                             test_id: Path(
-                                "Data::foo",
+                                "\"Data::foo\"",
                             ),
                         },
                         cfg: None,
@@ -1372,7 +1371,7 @@ impl Foo {
                         },
                         kind: DocTest {
                             test_id: Path(
-                                "foo::Foo::foo",
+                                "\"foo::Foo::foo\"",
                             ),
                         },
                         cfg: None,
@@ -2078,7 +2077,7 @@ impl<T, U> Foo<T, U> {
                         },
                         kind: DocTest {
                             test_id: Path(
-                                "Foo<T, U>::t",
+                                "\"Foo<T, U>::t\"",
                             ),
                         },
                         cfg: None,
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index 50187c933d..4eca69033a 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -115,10 +115,7 @@ fn signature_help_for_call(
         hir::CallableKind::Function(func) => {
             res.doc = func.docs(db).map(|it| it.into());
             format_to!(res.signature, "fn {}", func.name(db));
-            fn_params = Some(match func.self_param(db) {
-                Some(_self) => func.params_without_self(db),
-                None => func.assoc_fn_params(db),
-            });
+            fn_params = Some(func.assoc_fn_params(db));
         }
         hir::CallableKind::TupleStruct(strukt) => {
             res.doc = strukt.docs(db).map(|it| it.into());
@@ -1039,25 +1036,6 @@ fn f() {
         );
     }
 
-    #[test]
-    fn test_generic_param_in_method_call() {
-        check(
-            r#"
-struct Foo;
-impl Foo {
-    fn test<V>(&mut self, val: V) {}
-}
-fn sup() {
-    Foo.test($0)
-}
-"#,
-            expect![[r#"
-                fn test(&mut self, val: V)
-                                   ^^^^^^
-            "#]],
-        );
-    }
-
     #[test]
     fn test_generic_kinds() {
         check(
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 759494dcf0..7dc71cf710 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
     ast::{self, edit::AstNodeEdit, HasName},
-    AstNode, SmolStr, TextRange,
+    AstNode, TextRange,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -58,18 +58,9 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
                 }
                 let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
                     .filter_map(|it| it.name())
-                    .map(|name| SmolStr::from(name.text().trim_start_matches("r#")))
                     .collect::<Vec<_>>();
-
                 format_to!(buf, "{}", segments.into_iter().rev().format("/"));
-
-                // We need to special case mod named `r#mod` and place the file in a
-                // subdirectory as "mod.rs" would be of its parent module otherwise.
-                if module_name.text() == "r#mod" {
-                    format_to!(buf, "/mod.rs");
-                } else {
-                    format_to!(buf, ".rs");
-                }
+                format_to!(buf, ".rs");
                 buf
             };
             let contents = {
@@ -260,78 +251,4 @@ mod bar {
 "#,
         );
     }
-
-    #[test]
-    fn extract_mod_with_raw_ident() {
-        check_assist(
-            move_module_to_file,
-            r#"
-//- /main.rs
-mod $0r#static {}
-"#,
-            r#"
-//- /main.rs
-mod r#static;
-//- /static.rs
-"#,
-        )
-    }
-
-    #[test]
-    fn extract_r_mod() {
-        check_assist(
-            move_module_to_file,
-            r#"
-//- /main.rs
-mod $0r#mod {}
-"#,
-            r#"
-//- /main.rs
-mod r#mod;
-//- /mod/mod.rs
-"#,
-        )
-    }
-
-    #[test]
-    fn extract_r_mod_from_mod_rs() {
-        check_assist(
-            move_module_to_file,
-            r#"
-//- /main.rs
-mod foo;
-//- /foo/mod.rs
-mod $0r#mod {}
-"#,
-            r#"
-//- /foo/mod.rs
-mod r#mod;
-//- /foo/mod/mod.rs
-"#,
-        )
-    }
-
-    #[test]
-    fn extract_nested_r_mod() {
-        check_assist(
-            move_module_to_file,
-            r#"
-//- /main.rs
-mod r#mod {
-    mod foo {
-        mod $0r#mod {}
-    }
-}
-"#,
-            r#"
-//- /main.rs
-mod r#mod {
-    mod foo {
-        mod r#mod;
-    }
-}
-//- /mod/foo/mod/mod.rs
-"#,
-        )
-    }
 }
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 47cead7d57..c010c49489 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -15,7 +15,8 @@ use crate::{
 
 /// Complete repeated parameters, both name and type. For example, if all
 /// functions in a file have a `spam: &mut Spam` parameter, a completion with
-/// `spam: &mut Spam` insert text/label will be suggested.
+/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
+/// suggested.
 ///
 /// Also complete parameters for closure or local functions from the surrounding defined locals.
 pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -25,16 +26,14 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
     };
 
     let comma_wrapper = comma_wrapper(ctx);
-    let mut add_new_item_to_acc = |label: &str| {
+    let mut add_new_item_to_acc = |label: &str, lookup: String| {
         let mk_item = |label: &str, range: TextRange| {
             CompletionItem::new(CompletionItemKind::Binding, range, label)
         };
         let item = match &comma_wrapper {
-            Some((fmt, range)) => mk_item(&fmt(label), *range),
-            None => mk_item(label, ctx.source_range()),
+            Some((fmt, range, lookup)) => mk_item(&fmt(label), *range).lookup_by(lookup).to_owned(),
+            None => mk_item(label, ctx.source_range()).lookup_by(lookup).to_owned(),
         };
-        // Completion lookup is omitted intentionally here.
-        // See the full discussion: https://github.com/rust-lang/rust-analyzer/issues/12073
         item.add_to(acc)
     };
 
@@ -45,7 +44,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
         ParamKind::Closure(closure) => {
             let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?;
             params_from_stmt_list_scope(ctx, stmt_list, |name, ty| {
-                add_new_item_to_acc(&format!("{name}: {ty}"));
+                add_new_item_to_acc(&format!("{name}: {ty}"), name.to_string());
             });
         }
     }
@@ -57,7 +56,7 @@ fn fill_fn_params(
     ctx: &CompletionContext,
     function: &ast::Fn,
     param_list: &ast::ParamList,
-    mut add_new_item_to_acc: impl FnMut(&str),
+    mut add_new_item_to_acc: impl FnMut(&str, String),
 ) {
     let mut file_params = FxHashMap::default();
 
@@ -97,13 +96,18 @@ fn fill_fn_params(
             file_params.entry(format!("{name}: {ty}")).or_insert(name.to_string());
         });
     }
+
     remove_duplicated(&mut file_params, param_list.params());
     let self_completion_items = ["self", "&self", "mut self", "&mut self"];
     if should_add_self_completions(ctx, param_list) {
-        self_completion_items.into_iter().for_each(|self_item| add_new_item_to_acc(self_item));
+        self_completion_items
+            .into_iter()
+            .for_each(|self_item| add_new_item_to_acc(self_item, self_item.to_string()));
     }
 
-    file_params.keys().for_each(|whole_param| add_new_item_to_acc(whole_param));
+    file_params
+        .into_iter()
+        .for_each(|(whole_param, binding)| add_new_item_to_acc(&whole_param, binding));
 }
 
 fn params_from_stmt_list_scope(
@@ -157,7 +161,7 @@ fn should_add_self_completions(ctx: &CompletionContext, param_list: &ast::ParamL
     inside_impl && no_params
 }
 
-fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, TextRange)> {
+fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, TextRange, String)> {
     let param = ctx.token.ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?;
 
     let next_token_kind = {
@@ -179,5 +183,9 @@ fn comma_wrapper(ctx: &CompletionContext) -> Option<(impl Fn(&str) -> String, Te
         matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE);
     let leading = if has_leading_comma { "" } else { ", " };
 
-    Some((move |label: &_| (format!("{}{}{}", leading, label, trailing)), param.text_range()))
+    Some((
+        move |label: &_| (format!("{}{}{}", leading, label, trailing)),
+        param.text_range(),
+        format!("{}{}", leading, param.text()),
+    ))
 }
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index c00de6ff50..6a0e09dd64 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -43,7 +43,7 @@ pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionConte
 }
 
 pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionContext) {
-    if !(ctx.expects_item() || ctx.has_block_expr_parent())
+    if !ctx.expects_item()
         || ctx.previous_token_is(T![unsafe])
         || ctx.path_qual().is_some()
         || ctx.has_impl_or_trait_prev_sibling()
@@ -63,13 +63,11 @@ pub(crate) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte
         add_custom_completions(acc, ctx, cap, SnippetScope::Item);
     }
 
-    // Test-related snippets shouldn't be shown in blocks.
-    if !ctx.has_block_expr_parent() {
-        let mut item = snippet(
-            ctx,
-            cap,
-            "tmod (Test module)",
-            "\
+    let mut item = snippet(
+        ctx,
+        cap,
+        "tmod (Test module)",
+        "\
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -79,23 +77,22 @@ mod tests {
         $0
     }
 }",
-        );
-        item.lookup_by("tmod");
-        item.add_to(acc);
-
-        let mut item = snippet(
-            ctx,
-            cap,
-            "tfn (Test function)",
-            "\
+    );
+    item.lookup_by("tmod");
+    item.add_to(acc);
+
+    let mut item = snippet(
+        ctx,
+        cap,
+        "tfn (Test function)",
+        "\
 #[test]
 fn ${1:feature}() {
     $0
 }",
-        );
-        item.lookup_by("tfn");
-        item.add_to(acc);
-    }
+    );
+    item.lookup_by("tfn");
+    item.add_to(acc);
 
     let item = snippet(
         ctx,
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index d8183660e8..bd6833567c 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -570,7 +570,7 @@ fn main() {
     fn complete_fn_param() {
         // has mut kw
         check_edit(
-            "mut bar: u32",
+            "mut ba",
             r#"
 fn f(foo: (), mut bar: u32) {}
 fn g(foo: (), mut ba$0)
@@ -583,7 +583,7 @@ fn g(foo: (), mut bar: u32)
 
         // has type param
         check_edit(
-            "mut bar: u32",
+            "mut ba: u32",
             r#"
 fn g(foo: (), mut ba$0: u32)
 fn f(foo: (), mut bar: u32) {}
@@ -599,7 +599,7 @@ fn f(foo: (), mut bar: u32) {}
     fn complete_fn_mut_param_add_comma() {
         // add leading and trailing comma
         check_edit(
-            ", mut bar: u32,",
+            ", mut ba",
             r#"
 fn f(foo: (), mut bar: u32) {}
 fn g(foo: ()mut ba$0 baz: ())
@@ -614,7 +614,7 @@ fn g(foo: (), mut bar: u32, baz: ())
     #[test]
     fn complete_fn_mut_param_has_attribute() {
         check_edit(
-            r#"#[baz = "qux"] mut bar: u32"#,
+            "mut ba",
             r#"
 fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
 fn g(foo: (), mut ba$0)
@@ -626,7 +626,7 @@ fn g(foo: (), #[baz = "qux"] mut bar: u32)
         );
 
         check_edit(
-            r#"#[baz = "qux"] mut bar: u32"#,
+            r#"#[baz = "qux"] mut ba"#,
             r#"
 fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
 fn g(foo: (), #[baz = "qux"] mut ba$0)
@@ -638,7 +638,7 @@ fn g(foo: (), #[baz = "qux"] mut bar: u32)
         );
 
         check_edit(
-            r#", #[baz = "qux"] mut bar: u32"#,
+            r#", #[baz = "qux"] mut ba"#,
             r#"
 fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
 fn g(foo: ()#[baz = "qux"] mut ba$0)
diff --git a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
index 831d082bc7..ea0f35501b 100644
--- a/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/crates/ide_diagnostics/src/handlers/unresolved_macro_call.rs
@@ -1,5 +1,5 @@
 use hir::{db::AstDatabase, InFile};
-use syntax::{ast, AstNode, SyntaxNodePtr};
+use syntax::{AstNode, SyntaxNodePtr};
 
 use crate::{Diagnostic, DiagnosticsContext};
 
@@ -12,23 +12,19 @@ pub(crate) fn unresolved_macro_call(
     d: &hir::UnresolvedMacroCall,
 ) -> Diagnostic {
     let last_path_segment = ctx.sema.db.parse_or_expand(d.macro_call.file_id).and_then(|root| {
-        let node = d.macro_call.value.to_node(&root);
-        if let Some(macro_call) = ast::MacroCall::cast(node) {
-            macro_call
-                .path()
-                .and_then(|it| it.segment())
-                .and_then(|it| it.name_ref())
-                .map(|it| InFile::new(d.macro_call.file_id, SyntaxNodePtr::new(it.syntax())))
-        } else {
-            None
-        }
+        d.macro_call
+            .value
+            .to_node(&root)
+            .path()
+            .and_then(|it| it.segment())
+            .and_then(|it| it.name_ref())
+            .map(|it| InFile::new(d.macro_call.file_id, SyntaxNodePtr::new(it.syntax())))
     });
     let diagnostics = last_path_segment.unwrap_or_else(|| d.macro_call.clone().map(|it| it.into()));
 
-    let bang = if d.is_bang { "!" } else { "" };
     Diagnostic::new(
         "unresolved-macro-call",
-        format!("unresolved macro `{}{}`", d.path, bang),
+        format!("unresolved macro `{}!`", d.path),
         ctx.sema.diagnostics_display_range(diagnostics).range,
     )
     .experimental()
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 833ee31eed..ad1f9c40e2 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -584,7 +584,12 @@ impl Config {
                 scope,
             ) {
                 Some(snippet) => self.snippets.push(snippet),
-                None => tracing::info!("Invalid snippet {}", name),
+                None => errors.push((
+                    format!("snippet {name} is invalid"),
+                    <serde_json::Error as serde::de::Error>::custom(
+                        "snippet path is invalid or triggers are missing",
+                    ),
+                )),
             }
         }
 
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index cfbd5f63bc..ebd6f35b42 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -290,7 +290,7 @@ impl GlobalState {
             }
 
             let duration = start.elapsed();
-            tracing::info!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
+            tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
             self.send(response.into());
         }
     }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 96f4e2a50b..3870161826 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -314,7 +314,7 @@ impl GlobalState {
                             self.prime_caches_queue.op_completed(());
                             if cancelled {
                                 self.prime_caches_queue
-                                    .request_op("restart after cancelation".to_string());
+                                    .request_op("restart after cancellation".to_string());
                             }
                         }
                     };
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 286affbba9..3ea5844c95 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -11,7 +11,7 @@ use rustc_lexer::unescape::{
 
 use crate::{
     algo,
-    ast::{self, HasAttrs, HasVisibility},
+    ast::{self, HasVisibility},
     match_ast, AstNode, SyntaxError,
     SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
     SyntaxNode, SyntaxToken, TextSize, T,
@@ -231,9 +231,7 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
         Some(it) => it,
         None => return,
     };
-    // FIXME: disable validation if there's an attribute, since some proc macros use this syntax.
-    // ideally the validation would run only on the fully expanded code, then this wouldn't be necessary.
-    if impl_def.trait_().is_some() && impl_def.attrs().next().is_none() {
+    if impl_def.trait_().is_some() {
         errors.push(SyntaxError::new("Unnecessary visibility qualifier", vis.syntax.text_range()));
     }
 }


Test patch:
diff --git a/crates/ide_completion/src/tests/expression.rs b/crates/ide_completion/src/tests/expression.rs
index 5984149046..650c68134d 100644
--- a/crates/ide_completion/src/tests/expression.rs
+++ b/crates/ide_completion/src/tests/expression.rs
@@ -153,7 +153,6 @@ impl Unit {
             kw return
             sn pd
             sn ppd
-            sn macro_rules
             kw self
             kw super
             kw crate
@@ -247,11 +246,10 @@ fn complete_in_block() {
             kw return
             sn pd
             sn ppd
-            sn macro_rules
             kw self
             kw super
             kw crate
-            fn foo()       fn()
+            fn foo()     fn()
             bt u32
         "#]],
     )
@@ -295,11 +293,10 @@ fn complete_after_if_expr() {
             kw return
             sn pd
             sn ppd
-            sn macro_rules
             kw self
             kw super
             kw crate
-            fn foo()       fn()
+            fn foo()     fn()
             bt u32
         "#]],
     )
@@ -369,11 +366,10 @@ fn completes_in_loop_ctx() {
             kw return
             sn pd
             sn ppd
-            sn macro_rules
             kw self
             kw super
             kw crate
-            fn my()        fn()
+            fn my()      fn()
             bt u32
         "#]],
     );
diff --git a/crates/ide_completion/src/tests/fn_param.rs b/crates/ide_completion/src/tests/fn_param.rs
index 4578955da1..678c99aa7a 100644
--- a/crates/ide_completion/src/tests/fn_param.rs
+++ b/crates/ide_completion/src/tests/fn_param.rs
@@ -67,17 +67,6 @@ fn bar(file_id: u32, $0) {}
             kw mut
         "#]],
     );
-
-    check(
-        r#"
-fn f(#[foo = "bar"] baz: u32,) {}
-fn g(baz: (), ba$0)
-"#,
-        expect![[r##"
-                kw ref
-                kw mut
-            "##]],
-    )
 }
 
 #[test]