mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 21:25:25 +00:00 
			
		
		
		
	Merge pull request #19704 from Veykril/push-wrvznvvpvtvp
Add expression fill mode variant for filling with underscore expressions
This commit is contained in:
		
						commit
						0fee71065b
					
				
					 31 changed files with 172 additions and 125 deletions
				
			
		| 
						 | 
					@ -86,7 +86,7 @@ impl ModDir {
 | 
				
			||||||
                let dir_path = if root_dir_owner {
 | 
					                let dir_path = if root_dir_owner {
 | 
				
			||||||
                    DirPath::empty()
 | 
					                    DirPath::empty()
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    DirPath::new(format!("{}/", name))
 | 
					                    DirPath::new(format!("{name}/"))
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
 | 
					                if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
 | 
				
			||||||
                    return Ok((
 | 
					                    return Ok((
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -752,8 +752,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
 | 
				
			||||||
            err: Some(ExpandError::other(
 | 
					            err: Some(ExpandError::other(
 | 
				
			||||||
                tt.delimiter.open,
 | 
					                tt.delimiter.open,
 | 
				
			||||||
                format!(
 | 
					                format!(
 | 
				
			||||||
                    "macro invocation exceeds token limit: produced {} tokens, limit is {}",
 | 
					                    "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
 | 
				
			||||||
                    count, TOKEN_LIMIT,
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            )),
 | 
					            )),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,8 +206,7 @@ impl ExpandErrorKind {
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    None => RenderedExpandError {
 | 
					                    None => RenderedExpandError {
 | 
				
			||||||
                        message: format!(
 | 
					                        message: format!(
 | 
				
			||||||
                            "internal error: proc-macro map is missing error entry for crate {:?}",
 | 
					                            "internal error: proc-macro map is missing error entry for crate {def_crate:?}"
 | 
				
			||||||
                            def_crate
 | 
					 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                        error: true,
 | 
					                        error: true,
 | 
				
			||||||
                        kind: RenderedExpandError::GENERAL_KIND,
 | 
					                        kind: RenderedExpandError::GENERAL_KIND,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
//! assists if we are allowed to.
 | 
					//! assists if we are allowed to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use hir::ImportPathConfig;
 | 
					use hir::ImportPathConfig;
 | 
				
			||||||
use ide_db::{SnippetCap, imports::insert_use::InsertUseConfig};
 | 
					use ide_db::{SnippetCap, assists::ExprFillDefaultMode, imports::insert_use::InsertUseConfig};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::AssistKind;
 | 
					use crate::AssistKind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ pub struct AssistConfig {
 | 
				
			||||||
    pub term_search_fuel: u64,
 | 
					    pub term_search_fuel: u64,
 | 
				
			||||||
    pub term_search_borrowck: bool,
 | 
					    pub term_search_borrowck: bool,
 | 
				
			||||||
    pub code_action_grouping: bool,
 | 
					    pub code_action_grouping: bool,
 | 
				
			||||||
 | 
					    pub expr_fill_default: ExprFillDefaultMode,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl AssistConfig {
 | 
					impl AssistConfig {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,7 @@ fn add_missing_impl_members_inner(
 | 
				
			||||||
        let new_impl_def = edit.make_mut(impl_def.clone());
 | 
					        let new_impl_def = edit.make_mut(impl_def.clone());
 | 
				
			||||||
        let first_new_item = add_trait_assoc_items_to_impl(
 | 
					        let first_new_item = add_trait_assoc_items_to_impl(
 | 
				
			||||||
            &ctx.sema,
 | 
					            &ctx.sema,
 | 
				
			||||||
 | 
					            ctx.config,
 | 
				
			||||||
            &missing_items,
 | 
					            &missing_items,
 | 
				
			||||||
            trait_,
 | 
					            trait_,
 | 
				
			||||||
            &new_impl_def,
 | 
					            &new_impl_def,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ use std::iter::{self, Peekable};
 | 
				
			||||||
use either::Either;
 | 
					use either::Either;
 | 
				
			||||||
use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
 | 
					use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym};
 | 
				
			||||||
use ide_db::RootDatabase;
 | 
					use ide_db::RootDatabase;
 | 
				
			||||||
 | 
					use ide_db::assists::ExprFillDefaultMode;
 | 
				
			||||||
use ide_db::syntax_helpers::suggest_name;
 | 
					use ide_db::syntax_helpers::suggest_name;
 | 
				
			||||||
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 | 
					use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
| 
						 | 
					@ -216,7 +217,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 | 
				
			||||||
                    // filter out hidden patterns because they're handled by the catch-all arm
 | 
					                    // filter out hidden patterns because they're handled by the catch-all arm
 | 
				
			||||||
                    !hidden
 | 
					                    !hidden
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .map(|(pat, _)| make.match_arm(pat, None, make::ext::expr_todo()));
 | 
					                .map(|(pat, _)| {
 | 
				
			||||||
 | 
					                    make.match_arm(
 | 
				
			||||||
 | 
					                        pat,
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                        match ctx.config.expr_fill_default {
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut arms: Vec<_> = match_arm_list
 | 
					            let mut arms: Vec<_> = match_arm_list
 | 
				
			||||||
                .arms()
 | 
					                .arms()
 | 
				
			||||||
| 
						 | 
					@ -246,7 +257,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if needs_catch_all_arm && !has_catch_all_arm {
 | 
					            if needs_catch_all_arm && !has_catch_all_arm {
 | 
				
			||||||
                cov_mark::hit!(added_wildcard_pattern);
 | 
					                cov_mark::hit!(added_wildcard_pattern);
 | 
				
			||||||
                let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo());
 | 
					                let arm = make.match_arm(
 | 
				
			||||||
 | 
					                    make.wildcard_pat().into(),
 | 
				
			||||||
 | 
					                    None,
 | 
				
			||||||
 | 
					                    match ctx.config.expr_fill_default {
 | 
				
			||||||
 | 
					                        ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                        ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					                        ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
                arms.push(arm);
 | 
					                arms.push(arm);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,7 +142,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat
 | 
				
			||||||
        .map(|(id, ty)| {
 | 
					        .map(|(id, ty)| {
 | 
				
			||||||
            match name_generator.for_type(&ty, ctx.db(), ctx.edition()) {
 | 
					            match name_generator.for_type(&ty, ctx.db(), ctx.edition()) {
 | 
				
			||||||
                Some(name) => name,
 | 
					                Some(name) => name,
 | 
				
			||||||
                None => name_generator.suggest_name(&format!("_{}", id)),
 | 
					                None => name_generator.suggest_name(&format!("_{id}")),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            .to_string()
 | 
					            .to_string()
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ use hir::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap,
 | 
					    FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap,
 | 
				
			||||||
 | 
					    assists::ExprFillDefaultMode,
 | 
				
			||||||
    defs::{Definition, NameRefClass},
 | 
					    defs::{Definition, NameRefClass},
 | 
				
			||||||
    famous_defs::FamousDefs,
 | 
					    famous_defs::FamousDefs,
 | 
				
			||||||
    helpers::is_editable_crate,
 | 
					    helpers::is_editable_crate,
 | 
				
			||||||
| 
						 | 
					@ -276,7 +277,11 @@ impl FunctionBuilder {
 | 
				
			||||||
                target_module,
 | 
					                target_module,
 | 
				
			||||||
                &mut necessary_generic_params,
 | 
					                &mut necessary_generic_params,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            let placeholder_expr = make::ext::expr_todo();
 | 
					            let placeholder_expr = match ctx.config.expr_fill_default {
 | 
				
			||||||
 | 
					                ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					                ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
            fn_body = make::block_expr(vec![], Some(placeholder_expr));
 | 
					            fn_body = make::block_expr(vec![], Some(placeholder_expr));
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,7 +336,11 @@ impl FunctionBuilder {
 | 
				
			||||||
        let (generic_param_list, where_clause) =
 | 
					        let (generic_param_list, where_clause) =
 | 
				
			||||||
            fn_generic_params(ctx, necessary_generic_params, &target)?;
 | 
					            fn_generic_params(ctx, necessary_generic_params, &target)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let placeholder_expr = make::ext::expr_todo();
 | 
					        let placeholder_expr = match ctx.config.expr_fill_default {
 | 
				
			||||||
 | 
					            ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					            ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					            ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
 | 
					        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(Self {
 | 
					        Some(Self {
 | 
				
			||||||
| 
						 | 
					@ -444,7 +453,11 @@ fn make_fn_body_as_new_function(
 | 
				
			||||||
    let adt_info = adt_info.as_ref()?;
 | 
					    let adt_info = adt_info.as_ref()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let path_self = make::ext::ident_path("Self");
 | 
					    let path_self = make::ext::ident_path("Self");
 | 
				
			||||||
    let placeholder_expr = make::ext::expr_todo();
 | 
					    let placeholder_expr = match ctx.config.expr_fill_default {
 | 
				
			||||||
 | 
					        ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					        ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					        ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
 | 
					    let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
 | 
				
			||||||
        match strukt.kind(ctx.db()) {
 | 
					        match strukt.kind(ctx.db()) {
 | 
				
			||||||
            StructKind::Record => {
 | 
					            StructKind::Record => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ use syntax::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    AssistId,
 | 
					    AssistConfig, AssistId,
 | 
				
			||||||
    assist_context::{AssistContext, Assists, SourceChangeBuilder},
 | 
					    assist_context::{AssistContext, Assists, SourceChangeBuilder},
 | 
				
			||||||
    utils::{
 | 
					    utils::{
 | 
				
			||||||
        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
 | 
					        DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items,
 | 
				
			||||||
| 
						 | 
					@ -128,8 +128,14 @@ fn add_assist(
 | 
				
			||||||
    acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
 | 
					    acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| {
 | 
				
			||||||
        let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
 | 
					        let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
 | 
				
			||||||
        let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
 | 
					        let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false);
 | 
				
			||||||
        let impl_def_with_items =
 | 
					        let impl_def_with_items = impl_def_from_trait(
 | 
				
			||||||
            impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
 | 
					            &ctx.sema,
 | 
				
			||||||
 | 
					            ctx.config,
 | 
				
			||||||
 | 
					            adt,
 | 
				
			||||||
 | 
					            &annotated_name,
 | 
				
			||||||
 | 
					            trait_,
 | 
				
			||||||
 | 
					            replace_trait_path,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
 | 
					        update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let trait_path = make::ty_path(replace_trait_path.clone());
 | 
					        let trait_path = make::ty_path(replace_trait_path.clone());
 | 
				
			||||||
| 
						 | 
					@ -217,6 +223,7 @@ fn add_assist(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn impl_def_from_trait(
 | 
					fn impl_def_from_trait(
 | 
				
			||||||
    sema: &hir::Semantics<'_, ide_db::RootDatabase>,
 | 
					    sema: &hir::Semantics<'_, ide_db::RootDatabase>,
 | 
				
			||||||
 | 
					    config: &AssistConfig,
 | 
				
			||||||
    adt: &ast::Adt,
 | 
					    adt: &ast::Adt,
 | 
				
			||||||
    annotated_name: &ast::Name,
 | 
					    annotated_name: &ast::Name,
 | 
				
			||||||
    trait_: Option<hir::Trait>,
 | 
					    trait_: Option<hir::Trait>,
 | 
				
			||||||
| 
						 | 
					@ -241,7 +248,7 @@ fn impl_def_from_trait(
 | 
				
			||||||
    let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
 | 
					    let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let first_assoc_item =
 | 
					    let first_assoc_item =
 | 
				
			||||||
        add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope);
 | 
					        add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate a default `impl` function body for the derived trait.
 | 
					    // Generate a default `impl` function body for the derived trait.
 | 
				
			||||||
    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 | 
					    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ use expect_test::expect;
 | 
				
			||||||
use hir::Semantics;
 | 
					use hir::Semantics;
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    EditionedFileId, FileRange, RootDatabase, SnippetCap,
 | 
					    EditionedFileId, FileRange, RootDatabase, SnippetCap,
 | 
				
			||||||
 | 
					    assists::ExprFillDefaultMode,
 | 
				
			||||||
    base_db::SourceDatabase,
 | 
					    base_db::SourceDatabase,
 | 
				
			||||||
    imports::insert_use::{ImportGranularity, InsertUseConfig},
 | 
					    imports::insert_use::{ImportGranularity, InsertUseConfig},
 | 
				
			||||||
    source_change::FileSystemEdit,
 | 
					    source_change::FileSystemEdit,
 | 
				
			||||||
| 
						 | 
					@ -35,6 +36,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
 | 
				
			||||||
    term_search_fuel: 400,
 | 
					    term_search_fuel: 400,
 | 
				
			||||||
    term_search_borrowck: true,
 | 
					    term_search_borrowck: true,
 | 
				
			||||||
    code_action_grouping: true,
 | 
					    code_action_grouping: true,
 | 
				
			||||||
 | 
					    expr_fill_default: ExprFillDefaultMode::Todo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
 | 
					pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
 | 
				
			||||||
| 
						 | 
					@ -54,6 +56,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
 | 
				
			||||||
    term_search_fuel: 400,
 | 
					    term_search_fuel: 400,
 | 
				
			||||||
    term_search_borrowck: true,
 | 
					    term_search_borrowck: true,
 | 
				
			||||||
    code_action_grouping: false,
 | 
					    code_action_grouping: false,
 | 
				
			||||||
 | 
					    expr_fill_default: ExprFillDefaultMode::Todo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
 | 
					pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
 | 
				
			||||||
| 
						 | 
					@ -73,6 +76,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
 | 
				
			||||||
    term_search_fuel: 400,
 | 
					    term_search_fuel: 400,
 | 
				
			||||||
    term_search_borrowck: true,
 | 
					    term_search_borrowck: true,
 | 
				
			||||||
    code_action_grouping: true,
 | 
					    code_action_grouping: true,
 | 
				
			||||||
 | 
					    expr_fill_default: ExprFillDefaultMode::Todo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
 | 
					pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
 | 
				
			||||||
| 
						 | 
					@ -92,6 +96,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
 | 
				
			||||||
    term_search_fuel: 400,
 | 
					    term_search_fuel: 400,
 | 
				
			||||||
    term_search_borrowck: true,
 | 
					    term_search_borrowck: true,
 | 
				
			||||||
    code_action_grouping: true,
 | 
					    code_action_grouping: true,
 | 
				
			||||||
 | 
					    expr_fill_default: ExprFillDefaultMode::Todo,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
 | 
					pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ use hir::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    RootDatabase,
 | 
					    RootDatabase,
 | 
				
			||||||
 | 
					    assists::ExprFillDefaultMode,
 | 
				
			||||||
    famous_defs::FamousDefs,
 | 
					    famous_defs::FamousDefs,
 | 
				
			||||||
    path_transform::PathTransform,
 | 
					    path_transform::PathTransform,
 | 
				
			||||||
    syntax_helpers::{node_ext::preorder_expr, prettify_macro_expansion},
 | 
					    syntax_helpers::{node_ext::preorder_expr, prettify_macro_expansion},
 | 
				
			||||||
| 
						 | 
					@ -27,7 +28,10 @@ use syntax::{
 | 
				
			||||||
    ted,
 | 
					    ted,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::assist_context::{AssistContext, SourceChangeBuilder};
 | 
					use crate::{
 | 
				
			||||||
 | 
					    AssistConfig,
 | 
				
			||||||
 | 
					    assist_context::{AssistContext, SourceChangeBuilder},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod gen_trait_fn_body;
 | 
					mod gen_trait_fn_body;
 | 
				
			||||||
pub(crate) mod ref_field_expr;
 | 
					pub(crate) mod ref_field_expr;
 | 
				
			||||||
| 
						 | 
					@ -174,6 +178,7 @@ pub fn filter_assoc_items(
 | 
				
			||||||
/// inserted.
 | 
					/// inserted.
 | 
				
			||||||
pub fn add_trait_assoc_items_to_impl(
 | 
					pub fn add_trait_assoc_items_to_impl(
 | 
				
			||||||
    sema: &Semantics<'_, RootDatabase>,
 | 
					    sema: &Semantics<'_, RootDatabase>,
 | 
				
			||||||
 | 
					    config: &AssistConfig,
 | 
				
			||||||
    original_items: &[InFile<ast::AssocItem>],
 | 
					    original_items: &[InFile<ast::AssocItem>],
 | 
				
			||||||
    trait_: hir::Trait,
 | 
					    trait_: hir::Trait,
 | 
				
			||||||
    impl_: &ast::Impl,
 | 
					    impl_: &ast::Impl,
 | 
				
			||||||
| 
						 | 
					@ -219,7 +224,14 @@ pub fn add_trait_assoc_items_to_impl(
 | 
				
			||||||
        match &item {
 | 
					        match &item {
 | 
				
			||||||
            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
 | 
					            ast::AssocItem::Fn(fn_) if fn_.body().is_none() => {
 | 
				
			||||||
                let body = AstNodeEdit::indent(
 | 
					                let body = AstNodeEdit::indent(
 | 
				
			||||||
                    &make::block_expr(None, Some(make::ext::expr_todo())),
 | 
					                    &make::block_expr(
 | 
				
			||||||
 | 
					                        None,
 | 
				
			||||||
 | 
					                        Some(match config.expr_fill_default {
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					                            ExprFillDefaultMode::Default => make::ext::expr_todo(),
 | 
				
			||||||
 | 
					                        }),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                    new_indent_level,
 | 
					                    new_indent_level,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
 | 
					                ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,7 +135,7 @@ impl fmt::Debug for CompletionItem {
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                CompletionItemRefMode::Dereference => "*",
 | 
					                CompletionItemRefMode::Dereference => "*",
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            s.field("ref_match", &format!("{}@{offset:?}", prefix));
 | 
					            s.field("ref_match", &format!("{prefix}@{offset:?}"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if self.trigger_call_info {
 | 
					        if self.trigger_call_info {
 | 
				
			||||||
            s.field("trigger_call_info", &true);
 | 
					            s.field("trigger_call_info", &true);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,3 +169,15 @@ impl AssistResolveStrategy {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
pub struct GroupLabel(pub String);
 | 
					pub struct GroupLabel(pub String);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub enum ExprFillDefaultMode {
 | 
				
			||||||
 | 
					    Todo,
 | 
				
			||||||
 | 
					    Default,
 | 
				
			||||||
 | 
					    Underscore,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Default for ExprFillDefaultMode {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self::Todo
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,13 @@ use hir::{
 | 
				
			||||||
    sym,
 | 
					    sym,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    FxHashMap, assists::Assist, famous_defs::FamousDefs,
 | 
					    FxHashMap,
 | 
				
			||||||
    imports::import_assets::item_for_path_search, source_change::SourceChange,
 | 
					    assists::{Assist, ExprFillDefaultMode},
 | 
				
			||||||
    syntax_helpers::tree_diff::diff, text_edit::TextEdit,
 | 
					    famous_defs::FamousDefs,
 | 
				
			||||||
 | 
					    imports::import_assets::item_for_path_search,
 | 
				
			||||||
 | 
					    source_change::SourceChange,
 | 
				
			||||||
 | 
					    syntax_helpers::tree_diff::diff,
 | 
				
			||||||
 | 
					    text_edit::TextEdit,
 | 
				
			||||||
    use_trivial_constructor::use_trivial_constructor,
 | 
					    use_trivial_constructor::use_trivial_constructor,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use stdx::format_to;
 | 
					use stdx::format_to;
 | 
				
			||||||
| 
						 | 
					@ -102,8 +106,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
 | 
					            let generate_fill_expr = |ty: &Type| match ctx.config.expr_fill_default {
 | 
				
			||||||
                crate::ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
					                ExprFillDefaultMode::Todo => make::ext::expr_todo(),
 | 
				
			||||||
                crate::ExprFillDefaultMode::Default => {
 | 
					                ExprFillDefaultMode::Underscore => make::ext::expr_underscore(),
 | 
				
			||||||
 | 
					                ExprFillDefaultMode::Default => {
 | 
				
			||||||
                    get_default_constructor(ctx, d, ty).unwrap_or_else(make::ext::expr_todo)
 | 
					                    get_default_constructor(ctx, d, ty).unwrap_or_else(make::ext::expr_todo)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					use std::ops::Not;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use hir::{
 | 
					use hir::{
 | 
				
			||||||
    ClosureStyle, HirDisplay, ImportPathConfig,
 | 
					    ClosureStyle, HirDisplay, ImportPathConfig,
 | 
				
			||||||
    db::ExpandDatabase,
 | 
					    db::ExpandDatabase,
 | 
				
			||||||
| 
						 | 
					@ -60,9 +62,13 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut formatter = |_: &hir::Type| String::from("_");
 | 
					    let mut formatter = |_: &hir::Type| String::from("_");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let assists: Vec<Assist> = paths
 | 
					    let assists: Vec<Assist> = d
 | 
				
			||||||
 | 
					        .expected
 | 
				
			||||||
 | 
					        .is_unknown()
 | 
				
			||||||
 | 
					        .not()
 | 
				
			||||||
 | 
					        .then(|| "todo!()".to_owned())
 | 
				
			||||||
        .into_iter()
 | 
					        .into_iter()
 | 
				
			||||||
        .filter_map(|path| {
 | 
					        .chain(paths.into_iter().filter_map(|path| {
 | 
				
			||||||
            path.gen_source_code(
 | 
					            path.gen_source_code(
 | 
				
			||||||
                &scope,
 | 
					                &scope,
 | 
				
			||||||
                &mut formatter,
 | 
					                &mut formatter,
 | 
				
			||||||
| 
						 | 
					@ -75,7 +81,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
 | 
				
			||||||
                ctx.display_target,
 | 
					                ctx.display_target,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .ok()
 | 
					            .ok()
 | 
				
			||||||
        })
 | 
					        }))
 | 
				
			||||||
        .unique()
 | 
					        .unique()
 | 
				
			||||||
        .map(|code| Assist {
 | 
					        .map(|code| Assist {
 | 
				
			||||||
            id: AssistId::quick_fix("typed-hole"),
 | 
					            id: AssistId::quick_fix("typed-hole"),
 | 
				
			||||||
| 
						 | 
					@ -95,9 +101,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use crate::tests::{
 | 
					    use crate::tests::{check_diagnostics, check_fixes_unordered, check_has_fix};
 | 
				
			||||||
        check_diagnostics, check_fixes_unordered, check_has_fix, check_has_single_fix,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn unknown() {
 | 
					    fn unknown() {
 | 
				
			||||||
| 
						 | 
					@ -119,9 +123,9 @@ fn main() {
 | 
				
			||||||
    if _ {}
 | 
					    if _ {}
 | 
				
			||||||
     //^ 💡 error: invalid `_` expression, expected type `bool`
 | 
					     //^ 💡 error: invalid `_` expression, expected type `bool`
 | 
				
			||||||
    let _: fn() -> i32 = _;
 | 
					    let _: fn() -> i32 = _;
 | 
				
			||||||
                       //^ error: invalid `_` expression, expected type `fn() -> i32`
 | 
					                       //^ 💡 error: invalid `_` expression, expected type `fn() -> i32`
 | 
				
			||||||
    let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion*
 | 
					    let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion*
 | 
				
			||||||
                      //^ error: invalid `_` expression, expected type `fn()`
 | 
					                      //^ 💡 error: invalid `_` expression, expected type `fn()`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
"#,
 | 
					"#,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					@ -147,7 +151,7 @@ fn main() {
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
    let mut x = t();
 | 
					    let mut x = t();
 | 
				
			||||||
    x = _;
 | 
					    x = _;
 | 
				
			||||||
      //^ error: invalid `_` expression, expected type `&str`
 | 
					      //^ 💡 error: invalid `_` expression, expected type `&str`
 | 
				
			||||||
    x = "";
 | 
					    x = "";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
fn t<T>() -> T { loop {} }
 | 
					fn t<T>() -> T { loop {} }
 | 
				
			||||||
| 
						 | 
					@ -308,7 +312,7 @@ fn main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn ignore_impl_func_with_incorrect_return() {
 | 
					    fn ignore_impl_func_with_incorrect_return() {
 | 
				
			||||||
        check_has_single_fix(
 | 
					        check_fixes_unordered(
 | 
				
			||||||
            r#"
 | 
					            r#"
 | 
				
			||||||
struct Bar {}
 | 
					struct Bar {}
 | 
				
			||||||
trait Foo {
 | 
					trait Foo {
 | 
				
			||||||
| 
						 | 
					@ -323,7 +327,8 @@ fn main() {
 | 
				
			||||||
    let a: i32 = 1;
 | 
					    let a: i32 = 1;
 | 
				
			||||||
    let c: Bar = _$0;
 | 
					    let c: Bar = _$0;
 | 
				
			||||||
}"#,
 | 
					}"#,
 | 
				
			||||||
            r#"
 | 
					            vec![
 | 
				
			||||||
 | 
					                r#"
 | 
				
			||||||
struct Bar {}
 | 
					struct Bar {}
 | 
				
			||||||
trait Foo {
 | 
					trait Foo {
 | 
				
			||||||
    type Res;
 | 
					    type Res;
 | 
				
			||||||
| 
						 | 
					@ -337,6 +342,21 @@ fn main() {
 | 
				
			||||||
    let a: i32 = 1;
 | 
					    let a: i32 = 1;
 | 
				
			||||||
    let c: Bar = Bar {  };
 | 
					    let c: Bar = Bar {  };
 | 
				
			||||||
}"#,
 | 
					}"#,
 | 
				
			||||||
 | 
					                r#"
 | 
				
			||||||
 | 
					struct Bar {}
 | 
				
			||||||
 | 
					trait Foo {
 | 
				
			||||||
 | 
					    type Res;
 | 
				
			||||||
 | 
					    fn foo(&self) -> Self::Res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					impl Foo for i32 {
 | 
				
			||||||
 | 
					    type Res = Self;
 | 
				
			||||||
 | 
					    fn foo(&self) -> Self::Res { 1 }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    let a: i32 = 1;
 | 
				
			||||||
 | 
					    let c: Bar = todo!();
 | 
				
			||||||
 | 
					}"#,
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,7 +92,7 @@ use hir::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
 | 
					    EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
 | 
				
			||||||
    assists::{Assist, AssistId, AssistResolveStrategy},
 | 
					    assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode},
 | 
				
			||||||
    base_db::{ReleaseChannel, RootQueryDb as _},
 | 
					    base_db::{ReleaseChannel, RootQueryDb as _},
 | 
				
			||||||
    generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
 | 
					    generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
 | 
				
			||||||
    imports::insert_use::InsertUseConfig,
 | 
					    imports::insert_use::InsertUseConfig,
 | 
				
			||||||
| 
						 | 
					@ -219,17 +219,6 @@ impl Diagnostic {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, PartialEq, Eq)]
 | 
					 | 
				
			||||||
pub enum ExprFillDefaultMode {
 | 
					 | 
				
			||||||
    Todo,
 | 
					 | 
				
			||||||
    Default,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
impl Default for ExprFillDefaultMode {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        Self::Todo
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct DiagnosticsConfig {
 | 
					pub struct DiagnosticsConfig {
 | 
				
			||||||
    /// Whether native diagnostics are enabled.
 | 
					    /// Whether native diagnostics are enabled.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,14 +3,16 @@
 | 
				
			||||||
mod overly_long_real_world_cases;
 | 
					mod overly_long_real_world_cases;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    LineIndexDatabase, RootDatabase, assists::AssistResolveStrategy, base_db::SourceDatabase,
 | 
					    LineIndexDatabase, RootDatabase,
 | 
				
			||||||
 | 
					    assists::{AssistResolveStrategy, ExprFillDefaultMode},
 | 
				
			||||||
 | 
					    base_db::SourceDatabase,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
use stdx::trim_indent;
 | 
					use stdx::trim_indent;
 | 
				
			||||||
use test_fixture::WithFixture;
 | 
					use test_fixture::WithFixture;
 | 
				
			||||||
use test_utils::{MiniCore, assert_eq_text, extract_annotations};
 | 
					use test_utils::{MiniCore, assert_eq_text, extract_annotations};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity};
 | 
					use crate::{DiagnosticsConfig, Severity};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Takes a multi-file input fixture with annotated cursor positions,
 | 
					/// Takes a multi-file input fixture with annotated cursor positions,
 | 
				
			||||||
/// and checks that:
 | 
					/// and checks that:
 | 
				
			||||||
| 
						 | 
					@ -160,55 +162,6 @@ pub(crate) fn check_has_fix(
 | 
				
			||||||
    assert!(fix.is_some(), "no diagnostic with desired fix");
 | 
					    assert!(fix.is_some(), "no diagnostic with desired fix");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[track_caller]
 | 
					 | 
				
			||||||
pub(crate) fn check_has_single_fix(
 | 
					 | 
				
			||||||
    #[rust_analyzer::rust_fixture] ra_fixture_before: &str,
 | 
					 | 
				
			||||||
    #[rust_analyzer::rust_fixture] ra_fixture_after: &str,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    let after = trim_indent(ra_fixture_after);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
 | 
					 | 
				
			||||||
    let mut conf = DiagnosticsConfig::test_sample();
 | 
					 | 
				
			||||||
    conf.expr_fill_default = ExprFillDefaultMode::Default;
 | 
					 | 
				
			||||||
    let mut n_fixes = 0;
 | 
					 | 
				
			||||||
    let fix = super::full_diagnostics(
 | 
					 | 
				
			||||||
        &db,
 | 
					 | 
				
			||||||
        &conf,
 | 
					 | 
				
			||||||
        &AssistResolveStrategy::All,
 | 
					 | 
				
			||||||
        file_position.file_id.file_id(&db),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .into_iter()
 | 
					 | 
				
			||||||
    .find(|d| {
 | 
					 | 
				
			||||||
        d.fixes
 | 
					 | 
				
			||||||
            .as_ref()
 | 
					 | 
				
			||||||
            .and_then(|fixes| {
 | 
					 | 
				
			||||||
                n_fixes += fixes.len();
 | 
					 | 
				
			||||||
                fixes.iter().find(|fix| {
 | 
					 | 
				
			||||||
                    if !fix.target.contains_inclusive(file_position.offset) {
 | 
					 | 
				
			||||||
                        return false;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    let actual = {
 | 
					 | 
				
			||||||
                        let source_change = fix.source_change.as_ref().unwrap();
 | 
					 | 
				
			||||||
                        let file_id = *source_change.source_file_edits.keys().next().unwrap();
 | 
					 | 
				
			||||||
                        let mut actual = db.file_text(file_id).text(&db).to_string();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        for (edit, snippet_edit) in source_change.source_file_edits.values() {
 | 
					 | 
				
			||||||
                            edit.apply(&mut actual);
 | 
					 | 
				
			||||||
                            if let Some(snippet_edit) = snippet_edit {
 | 
					 | 
				
			||||||
                                snippet_edit.apply(&mut actual);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        actual
 | 
					 | 
				
			||||||
                    };
 | 
					 | 
				
			||||||
                    after == actual
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .is_some()
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    assert!(fix.is_some(), "no diagnostic with desired fix");
 | 
					 | 
				
			||||||
    assert!(n_fixes == 1, "Too many fixes suggested");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Checks that there's a diagnostic *without* fix at `$0`.
 | 
					/// Checks that there's a diagnostic *without* fix at `$0`.
 | 
				
			||||||
pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
 | 
					pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
 | 
				
			||||||
    let (db, file_position) = RootDatabase::with_position(ra_fixture);
 | 
					    let (db, file_position) = RootDatabase::with_position(ra_fixture);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -599,7 +599,7 @@ fn filename_and_frag_for_def(
 | 
				
			||||||
            Some(name) => {
 | 
					            Some(name) => {
 | 
				
			||||||
                match m.attrs(db).by_key(sym::doc).find_string_value_in_tt(sym::keyword) {
 | 
					                match m.attrs(db).by_key(sym::doc).find_string_value_in_tt(sym::keyword) {
 | 
				
			||||||
                    Some(kw) => {
 | 
					                    Some(kw) => {
 | 
				
			||||||
                        format!("keyword.{}.html", kw)
 | 
					                        format!("keyword.{kw}.html")
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    None => format!("{}/index.html", name.as_str()),
 | 
					                    None => format!("{}/index.html", name.as_str()),
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,9 +123,9 @@ pub use ide_completion::{
 | 
				
			||||||
    CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
 | 
					    CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
 | 
				
			||||||
    CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope,
 | 
					    CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
pub use ide_db::text_edit::{Indel, TextEdit};
 | 
					 | 
				
			||||||
pub use ide_db::{
 | 
					pub use ide_db::{
 | 
				
			||||||
    FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
 | 
					    FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
 | 
				
			||||||
 | 
					    assists::ExprFillDefaultMode,
 | 
				
			||||||
    base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId},
 | 
					    base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId},
 | 
				
			||||||
    documentation::Documentation,
 | 
					    documentation::Documentation,
 | 
				
			||||||
    label::Label,
 | 
					    label::Label,
 | 
				
			||||||
| 
						 | 
					@ -134,8 +134,9 @@ pub use ide_db::{
 | 
				
			||||||
    search::{ReferenceCategory, SearchScope},
 | 
					    search::{ReferenceCategory, SearchScope},
 | 
				
			||||||
    source_change::{FileSystemEdit, SnippetEdit, SourceChange},
 | 
					    source_change::{FileSystemEdit, SnippetEdit, SourceChange},
 | 
				
			||||||
    symbol_index::Query,
 | 
					    symbol_index::Query,
 | 
				
			||||||
 | 
					    text_edit::{Indel, TextEdit},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode};
 | 
					pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig};
 | 
				
			||||||
pub use ide_ssr::SsrError;
 | 
					pub use ide_ssr::SsrError;
 | 
				
			||||||
pub use span::Edition;
 | 
					pub use span::Edition;
 | 
				
			||||||
pub use syntax::{TextRange, TextSize};
 | 
					pub use syntax::{TextRange, TextSize};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -451,7 +451,7 @@ mod tests {
 | 
				
			||||||
        assert_eq!(x.len(), 1);
 | 
					        assert_eq!(x.len(), 1);
 | 
				
			||||||
        match x.into_iter().next().unwrap() {
 | 
					        match x.into_iter().next().unwrap() {
 | 
				
			||||||
            MonikerResult::Local { enclosing_moniker } => {
 | 
					            MonikerResult::Local { enclosing_moniker } => {
 | 
				
			||||||
                panic!("Unexpected local enclosed in {:?}", enclosing_moniker);
 | 
					                panic!("Unexpected local enclosed in {enclosing_moniker:?}");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            MonikerResult::Moniker(x) => {
 | 
					            MonikerResult::Moniker(x) => {
 | 
				
			||||||
                assert_eq!(identifier, x.identifier.to_string());
 | 
					                assert_eq!(identifier, x.identifier.to_string());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,8 +51,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
 | 
				
			||||||
                buf,
 | 
					                buf,
 | 
				
			||||||
                "Crate: {}\n",
 | 
					                "Crate: {}\n",
 | 
				
			||||||
                match display_name {
 | 
					                match display_name {
 | 
				
			||||||
                    Some(it) => format!("{it}({:?})", crate_id),
 | 
					                    Some(it) => format!("{it}({crate_id:?})"),
 | 
				
			||||||
                    None => format!("{:?}", crate_id),
 | 
					                    None => format!("{crate_id:?}"),
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            format_to!(buf, "    Root module file id: {}\n", root_file_id.index());
 | 
					            format_to!(buf, "    Root module file id: {}\n", root_file_id.index());
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,7 +80,7 @@ impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn node_id(&'a self, n: &Crate) -> Id<'a> {
 | 
					    fn node_id(&'a self, n: &Crate) -> Id<'a> {
 | 
				
			||||||
        let id = n.as_id().as_u32();
 | 
					        let id = n.as_id().as_u32();
 | 
				
			||||||
        Id::new(format!("_{:?}", id)).unwrap()
 | 
					        Id::new(format!("_{id:?}")).unwrap()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn node_shape(&'a self, _node: &Crate) -> Option<LabelText<'a>> {
 | 
					    fn node_shape(&'a self, _node: &Crate) -> Option<LabelText<'a>> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,5 +12,5 @@ fn main() {
 | 
				
			||||||
    let version_string = std::str::from_utf8(&output.stdout[..])
 | 
					    let version_string = std::str::from_utf8(&output.stdout[..])
 | 
				
			||||||
        .expect("rustc --version output must be UTF-8")
 | 
					        .expect("rustc --version output must be UTF-8")
 | 
				
			||||||
        .trim();
 | 
					        .trim();
 | 
				
			||||||
    println!("cargo::rustc-env=RUSTC_VERSION={}", version_string);
 | 
					    println!("cargo::rustc-env=RUSTC_VERSION={version_string}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ impl LoggerDb {
 | 
				
			||||||
    /// it is meant to be run from outside any tracked functions.
 | 
					    /// it is meant to be run from outside any tracked functions.
 | 
				
			||||||
    pub(crate) fn assert_logs(&self, expected: expect_test::Expect) {
 | 
					    pub(crate) fn assert_logs(&self, expected: expect_test::Expect) {
 | 
				
			||||||
        let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap());
 | 
					        let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap());
 | 
				
			||||||
        expected.assert_eq(&format!("{:#?}", logs));
 | 
					        expected.assert_eq(&format!("{logs:#?}"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -175,7 +175,7 @@ impl flags::AnalysisStats {
 | 
				
			||||||
            UsizeWithUnderscore(dep_loc),
 | 
					            UsizeWithUnderscore(dep_loc),
 | 
				
			||||||
            UsizeWithUnderscore(dep_item_trees),
 | 
					            UsizeWithUnderscore(dep_item_trees),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        eprintln!("  dependency item stats: {}", dep_item_stats);
 | 
					        eprintln!("  dependency item stats: {dep_item_stats}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // FIXME(salsa-transition): bring back stats for ParseQuery (file size)
 | 
					        // FIXME(salsa-transition): bring back stats for ParseQuery (file size)
 | 
				
			||||||
        // and ParseMacroExpansionQuery (macro expansion "file") size whenever we implement
 | 
					        // and ParseMacroExpansionQuery (macro expansion "file") size whenever we implement
 | 
				
			||||||
| 
						 | 
					@ -295,7 +295,7 @@ impl flags::AnalysisStats {
 | 
				
			||||||
            UsizeWithUnderscore(workspace_loc),
 | 
					            UsizeWithUnderscore(workspace_loc),
 | 
				
			||||||
            UsizeWithUnderscore(workspace_item_trees),
 | 
					            UsizeWithUnderscore(workspace_item_trees),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        eprintln!("    usages: {}", workspace_item_stats);
 | 
					        eprintln!("    usages: {workspace_item_stats}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        eprintln!("  Dependencies:");
 | 
					        eprintln!("  Dependencies:");
 | 
				
			||||||
        eprintln!(
 | 
					        eprintln!(
 | 
				
			||||||
| 
						 | 
					@ -303,7 +303,7 @@ impl flags::AnalysisStats {
 | 
				
			||||||
            UsizeWithUnderscore(dep_loc),
 | 
					            UsizeWithUnderscore(dep_loc),
 | 
				
			||||||
            UsizeWithUnderscore(dep_item_trees),
 | 
					            UsizeWithUnderscore(dep_item_trees),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        eprintln!("    declarations: {}", dep_item_stats);
 | 
					        eprintln!("    declarations: {dep_item_stats}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let crate_def_map_time = crate_def_map_sw.elapsed();
 | 
					        let crate_def_map_time = crate_def_map_sw.elapsed();
 | 
				
			||||||
        eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time);
 | 
					        eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time);
 | 
				
			||||||
| 
						 | 
					@ -1294,7 +1294,7 @@ impl fmt::Display for UsizeWithUnderscore {
 | 
				
			||||||
        let num_str = self.0.to_string();
 | 
					        let num_str = self.0.to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if num_str.len() <= 3 {
 | 
					        if num_str.len() <= 3 {
 | 
				
			||||||
            return write!(f, "{}", num_str);
 | 
					            return write!(f, "{num_str}");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut result = String::new();
 | 
					        let mut result = String::new();
 | 
				
			||||||
| 
						 | 
					@ -1307,7 +1307,7 @@ impl fmt::Display for UsizeWithUnderscore {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let result = result.chars().rev().collect::<String>();
 | 
					        let result = result.chars().rev().collect::<String>();
 | 
				
			||||||
        write!(f, "{}", result)
 | 
					        write!(f, "{result}")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,10 +265,10 @@ impl flags::Scip {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if !duplicate_symbol_errors.is_empty() {
 | 
					        if !duplicate_symbol_errors.is_empty() {
 | 
				
			||||||
            eprintln!("{}", DUPLICATE_SYMBOLS_MESSAGE);
 | 
					            eprintln!("{DUPLICATE_SYMBOLS_MESSAGE}");
 | 
				
			||||||
            for (source_location, symbol) in duplicate_symbol_errors {
 | 
					            for (source_location, symbol) in duplicate_symbol_errors {
 | 
				
			||||||
                eprintln!("{}", source_location);
 | 
					                eprintln!("{source_location}");
 | 
				
			||||||
                eprintln!("  Duplicate symbol: {}", symbol);
 | 
					                eprintln!("  Duplicate symbol: {symbol}");
 | 
				
			||||||
                eprintln!();
 | 
					                eprintln!();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,13 +9,14 @@ use cfg::{CfgAtom, CfgDiff};
 | 
				
			||||||
use hir::Symbol;
 | 
					use hir::Symbol;
 | 
				
			||||||
use ide::{
 | 
					use ide::{
 | 
				
			||||||
    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
 | 
					    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
 | 
				
			||||||
    CompletionFieldsToResolve, DiagnosticsConfig, ExprFillDefaultMode, GenericParameterHints,
 | 
					    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
 | 
				
			||||||
    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
 | 
					    HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
 | 
				
			||||||
    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
 | 
					    JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
 | 
				
			||||||
    Snippet, SnippetScope, SourceRootId,
 | 
					    SourceRootId,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use ide_db::{
 | 
					use ide_db::{
 | 
				
			||||||
    SnippetCap,
 | 
					    SnippetCap,
 | 
				
			||||||
 | 
					    assists::ExprFillDefaultMode,
 | 
				
			||||||
    imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 | 
					    imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use itertools::{Either, Itertools};
 | 
					use itertools::{Either, Itertools};
 | 
				
			||||||
| 
						 | 
					@ -1493,6 +1494,11 @@ impl Config {
 | 
				
			||||||
            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
 | 
					            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
 | 
				
			||||||
            term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
 | 
					            term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
 | 
				
			||||||
            code_action_grouping: self.code_action_group(),
 | 
					            code_action_grouping: self.code_action_group(),
 | 
				
			||||||
 | 
					            expr_fill_default: match self.assist_expressionFillDefault(source_root) {
 | 
				
			||||||
 | 
					                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
 | 
				
			||||||
 | 
					                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
 | 
				
			||||||
 | 
					                ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1577,6 +1583,7 @@ impl Config {
 | 
				
			||||||
            expr_fill_default: match self.assist_expressionFillDefault(source_root) {
 | 
					            expr_fill_default: match self.assist_expressionFillDefault(source_root) {
 | 
				
			||||||
                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
 | 
					                ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
 | 
				
			||||||
                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
 | 
					                ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
 | 
				
			||||||
 | 
					                ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore,
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            snippet_cap: self.snippet_cap(),
 | 
					            snippet_cap: self.snippet_cap(),
 | 
				
			||||||
            insert_use: self.insert_use_config(source_root),
 | 
					            insert_use: self.insert_use_config(source_root),
 | 
				
			||||||
| 
						 | 
					@ -2527,6 +2534,7 @@ where
 | 
				
			||||||
enum ExprFillDefaultDef {
 | 
					enum ExprFillDefaultDef {
 | 
				
			||||||
    Todo,
 | 
					    Todo,
 | 
				
			||||||
    Default,
 | 
					    Default,
 | 
				
			||||||
 | 
					    Underscore,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
					#[derive(Serialize, Deserialize, Debug, Clone)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,6 +69,9 @@ pub mod ext {
 | 
				
			||||||
    pub fn expr_todo() -> ast::Expr {
 | 
					    pub fn expr_todo() -> ast::Expr {
 | 
				
			||||||
        expr_from_text("todo!()")
 | 
					        expr_from_text("todo!()")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn expr_underscore() -> ast::Expr {
 | 
				
			||||||
 | 
					        expr_from_text("_")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
 | 
					    pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
 | 
				
			||||||
        expr_from_text(&format!("{ty}::default()"))
 | 
					        expr_from_text(&format!("{ty}::default()"))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -728,9 +728,9 @@ fn print_debug_subtree<S: fmt::Debug>(
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    write!(f, "{align}SUBTREE {delim} ",)?;
 | 
					    write!(f, "{align}SUBTREE {delim} ",)?;
 | 
				
			||||||
    write!(f, "{:#?}", open)?;
 | 
					    write!(f, "{open:#?}")?;
 | 
				
			||||||
    write!(f, " ")?;
 | 
					    write!(f, " ")?;
 | 
				
			||||||
    write!(f, "{:#?}", close)?;
 | 
					    write!(f, "{close:#?}")?;
 | 
				
			||||||
    for child in iter {
 | 
					    for child in iter {
 | 
				
			||||||
        writeln!(f)?;
 | 
					        writeln!(f)?;
 | 
				
			||||||
        print_debug_token(f, level + 1, child)?;
 | 
					        print_debug_token(f, level + 1, child)?;
 | 
				
			||||||
| 
						 | 
					@ -855,7 +855,7 @@ impl<S> fmt::Display for Literal<S> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }?;
 | 
					        }?;
 | 
				
			||||||
        if let Some(suffix) = &self.suffix {
 | 
					        if let Some(suffix) = &self.suffix {
 | 
				
			||||||
            write!(f, "{}", suffix)?;
 | 
					            write!(f, "{suffix}")?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -414,7 +414,7 @@ fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String {
 | 
				
			||||||
        .map(|kind| to_pascal_case(kind))
 | 
					        .map(|kind| to_pascal_case(kind))
 | 
				
			||||||
        .filter(|name| !defined_nodes.iter().any(|&it| it == name))
 | 
					        .filter(|name| !defined_nodes.iter().any(|&it| it == name))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        eprintln!("Warning: node {} not defined in AST source", node);
 | 
					        eprintln!("Warning: node {node} not defined in AST source");
 | 
				
			||||||
        drop(node);
 | 
					        drop(node);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,7 +159,7 @@ fn collect_tests(s: &str) -> Vec<Test> {
 | 
				
			||||||
                (name.to_owned(), Some(edition.to_owned()))
 | 
					                (name.to_owned(), Some(edition.to_owned()))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            [name] => (name.to_owned(), None),
 | 
					            [name] => (name.to_owned(), None),
 | 
				
			||||||
            _ => panic!("invalid test name: {:?}", name),
 | 
					            _ => panic!("invalid test name: {name:?}"),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let text: String = edition
 | 
					        let text: String = edition
 | 
				
			||||||
            .as_ref()
 | 
					            .as_ref()
 | 
				
			||||||
| 
						 | 
					@ -212,7 +212,7 @@ fn existing_tests(dir: &Path, ok: TestKind) -> Result<HashMap<String, (PathBuf,
 | 
				
			||||||
                text.lines().next().and_then(|it| it.strip_prefix("// ")).map(ToOwned::to_owned);
 | 
					                text.lines().next().and_then(|it| it.strip_prefix("// ")).map(ToOwned::to_owned);
 | 
				
			||||||
            let test = Test { name: name.clone(), text, kind: ok, edition };
 | 
					            let test = Test { name: name.clone(), text, kind: ok, edition };
 | 
				
			||||||
            if let Some(old) = res.insert(name, (path, test)) {
 | 
					            if let Some(old) = res.insert(name, (path, test)) {
 | 
				
			||||||
                println!("Duplicate test: {:?}", old);
 | 
					                println!("Duplicate test: {old:?}");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue