File is large — showing lines 1–2,000 of 4,103.
1use std::{iter, mem::discriminant};23use crate::Analysis;4use crate::{5 FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,6 doc_links::token_as_doc_comment,7 navigation_target::{self, ToNav},8};9use hir::{10 AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,11};12use ide_db::ra_fixture::{RaFixtureConfig, UpmapFromRaFixture};13use ide_db::{14 RootDatabase, SymbolKind,15 base_db::{AnchoredPath, SourceDatabase},16 defs::{Definition, IdentClass},17 famous_defs::FamousDefs,18 helpers::pick_best_token,19 syntax_helpers::node_ext::find_loops,20};21use itertools::Itertools;22use span::FileId;23use syntax::{24 AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange, ast, match_ast,25};2627#[derive(Debug)]28pub struct GotoDefinitionConfig<'a> {29 pub ra_fixture: RaFixtureConfig<'a>,30}3132// Feature: Go to Definition33//34// Navigates to the definition of an identifier.35//36// For outline modules, this will navigate to the source file of the module.37//38// | Editor | Shortcut |39// |---------|----------|40// | VS Code | <kbd>F12</kbd> |41//42// 43pub(crate) fn goto_definition(44 db: &RootDatabase,45 FilePosition { file_id, offset }: FilePosition,46 config: &GotoDefinitionConfig<'_>,47) -> Option<RangeInfo<Vec<NavigationTarget>>> {48 let sema = &Semantics::new(db);49 let file = sema.parse_guess_edition(file_id).syntax().clone();50 let edition = sema.attach_first_edition(file_id).edition(db);51 let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {52 IDENT53 | INT_NUMBER54 | LIFETIME_IDENT55 | T![self]56 | T![super]57 | T![crate]58 | T![Self]59 | COMMENT => 4,60 // index and prefix ops61 T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,62 kind if kind.is_keyword(edition) => 2,63 T!['('] | T![')'] => 2,64 kind if kind.is_trivia() => 0,65 _ => 1,66 })?;67 if let Some(doc_comment) = token_as_doc_comment(&original_token) {68 return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {69 let nav = def.try_to_nav(sema)?;70 Some(RangeInfo::new(link_range, nav.collect()))71 });72 }7374 if let Some((range, _, _, resolution)) =75 sema.check_for_format_args_template(original_token.clone(), offset)76 {77 return Some(RangeInfo::new(78 range,79 match resolution {80 Some(res) => def_to_nav(sema, Definition::from(res)),81 None => vec![],82 },83 ));84 }8586 if let Some(navs) = handle_control_flow_keywords(sema, &original_token) {87 return Some(RangeInfo::new(original_token.text_range(), navs));88 }8990 let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);91 let mut navs = Vec::new();92 for token in tokens {93 if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {94 navs.extend(n);95 continue;96 }9798 let parent = token.value.parent()?;99100 if let Some(question_mark_conversion) = goto_question_mark_conversions(sema, &parent) {101 navs.extend(def_to_nav(sema, question_mark_conversion.into()));102 continue;103 }104105 if let Some(token) = ast::String::cast(token.value.clone())106 && let Some(original_token) = ast::String::cast(original_token.clone())107 && let Some((analysis, fixture_analysis)) =108 Analysis::from_ra_fixture(sema, original_token, &token, &config.ra_fixture)109 && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)110 {111 return hir::attach_db_allow_change(&analysis.db, || {112 goto_definition(113 &analysis.db,114 FilePosition { file_id: virtual_file_id, offset: file_offset },115 config,116 )117 })118 .and_then(|navs| {119 navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()120 });121 }122123 let token_file_id = token.file_id;124 if let Some(token) = ast::String::cast(token.value.clone())125 && let Some(x) =126 try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)127 {128 navs.push(x);129 continue;130 }131132 if ast::TokenTree::can_cast(parent.kind())133 && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)134 {135 navs.push(x);136 continue;137 }138139 let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };140 navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {141 if let Definition::ExternCrateDecl(crate_def) = def {142 return crate_def143 .resolved_crate(db)144 .map(|it| it.root_module(db).to_nav(db))145 .into_iter()146 .flatten()147 .collect();148 }149 try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))150 }));151 }152 let navs = navs.into_iter().unique().collect();153154 Some(RangeInfo::new(original_token.text_range(), navs))155}156157/// When the `?` operator is used on `Result`, go to the `From` impl if it exists as this provides more value.158fn goto_question_mark_conversions(159 sema: &Semantics<'_, RootDatabase>,160 node: &SyntaxNode,161) -> Option<hir::Function> {162 let node = ast::TryExpr::cast(node.clone())?;163 let try_expr_ty = sema.type_of_expr(&node.expr()?)?.adjusted();164165 let fd = FamousDefs(sema, try_expr_ty.krate(sema.db));166 let result_enum = fd.core_result_Result()?.into();167168 let (try_expr_ty_adt, try_expr_ty_args) = try_expr_ty.as_adt_with_args()?;169 if try_expr_ty_adt != result_enum {170 // FIXME: Support `Poll<Result>`.171 return None;172 }173 let original_err_ty = try_expr_ty_args.get(1)?.clone()?;174175 let returned_ty = sema.try_expr_returned_type(&node)?;176 let (returned_adt, returned_ty_args) = returned_ty.as_adt_with_args()?;177 if returned_adt != result_enum {178 return None;179 }180 let returned_err_ty = returned_ty_args.get(1)?.clone()?;181182 if returned_err_ty.could_unify_with_deeply(sema.db, &original_err_ty) {183 return None;184 }185186 let from_trait = fd.core_convert_From()?;187 let from_fn = from_trait.function(sema.db, sym::from)?;188 sema.resolve_trait_impl_method(189 returned_err_ty.clone(),190 from_trait,191 from_fn,192 [returned_err_ty, original_err_ty],193 )194}195196// If the token is into(), try_into(), search the definition of From, TryFrom.197fn find_definition_for_known_blanket_dual_impls(198 sema: &Semantics<'_, RootDatabase>,199 original_token: &SyntaxToken,200) -> Option<Vec<NavigationTarget>> {201 let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;202 let callable = sema.resolve_method_call_as_callable(&method_call)?;203 let CallableKind::Function(f) = callable.kind() else { return None };204 let assoc = f.as_assoc_item(sema.db)?;205206 let return_type = callable.return_type();207 let fd = FamousDefs(sema, return_type.krate(sema.db));208209 let t = match assoc.container(sema.db) {210 hir::AssocItemContainer::Trait(t) => t,211 hir::AssocItemContainer::Impl(impl_)212 if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>213 {214 let t = fd.core_convert_FromStr()?;215 let t_f = t.function(sema.db, &sym::from_str)?;216 return sema217 .resolve_trait_impl_method(218 return_type.clone(),219 t,220 t_f,221 [return_type.type_arguments().next()?],222 )223 .map(|f| def_to_nav(sema, f.into()));224 }225 hir::AssocItemContainer::Impl(_) => return None,226 };227228 let fn_name = f.name(sema.db);229 let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {230 let dual = fd.core_convert_From()?;231 let dual_f = dual.function(sema.db, &sym::from)?;232 sema.resolve_trait_impl_method(233 return_type.clone(),234 dual,235 dual_f,236 [return_type, callable.receiver_param(sema.db)?.1],237 )?238 } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {239 let dual = fd.core_convert_TryFrom()?;240 let dual_f = dual.function(sema.db, &sym::try_from)?;241 sema.resolve_trait_impl_method(242 return_type.clone(),243 dual,244 dual_f,245 // Extract the `T` from `Result<T, ..>`246 [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],247 )?248 } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {249 let dual = fd.core_fmt_Display()?;250 let dual_f = dual.function(sema.db, &sym::fmt)?;251 sema.resolve_trait_impl_method(252 return_type.clone(),253 dual,254 dual_f,255 [callable.receiver_param(sema.db)?.1.strip_reference()],256 )?257 } else {258 return None;259 };260 // Assert that we got a trait impl function, if we are back in a trait definition we didn't261 // succeed262 let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;263 let def = Definition::from(f);264 Some(def_to_nav(sema, def))265}266267fn try_lookup_include_path(268 sema: &Semantics<'_, RootDatabase>,269 token: InFile<ast::String>,270 file_id: FileId,271) -> Option<NavigationTarget> {272 let file = token.file_id.macro_file()?;273274 // Check that we are in the eager argument expansion of an include macro275 // that is we are the string input of it276 if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())277 .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())278 {279 return None;280 }281 let path = token.value.value().ok()?;282283 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;284 let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;285 Some(NavigationTarget {286 file_id,287 full_range: TextRange::new(0.into(), size),288 name: hir::Symbol::intern(&path),289 alias: None,290 focus_range: None,291 kind: None,292 container_name: None,293 description: None,294 docs: None,295 })296}297298fn try_lookup_macro_def_in_macro_use(299 sema: &Semantics<'_, RootDatabase>,300 token: SyntaxToken,301) -> Option<NavigationTarget> {302 let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?;303 let extern_crate = sema.to_def(&extern_crate)?;304 let krate = extern_crate.resolved_crate(sema.db)?;305306 for mod_def in krate.root_module(sema.db).declarations(sema.db) {307 if let ModuleDef::Macro(mac) = mod_def308 && mac.name(sema.db).as_str() == token.text()309 && let Some(nav) = mac.try_to_nav(sema)310 {311 return Some(nav.call_site);312 }313 }314315 None316}317318/// finds the trait definition of an impl'd item, except function319/// e.g.320/// ```rust321/// trait A { type a; }322/// struct S;323/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait324/// ```325fn try_filter_trait_item_definition(326 sema: &Semantics<'_, RootDatabase>,327 def: &Definition,328) -> Option<Vec<NavigationTarget>> {329 let db = sema.db;330 let assoc = def.as_assoc_item(db)?;331 match assoc {332 AssocItem::Function(..) => None,333 AssocItem::Const(..) | AssocItem::TypeAlias(..) => {334 let trait_ = assoc.implemented_trait(db)?;335 let name = def.name(db)?;336 let discriminant_value = discriminant(&assoc);337 trait_338 .items(db)339 .iter()340 .filter(|itm| discriminant(*itm) == discriminant_value)341 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten())342 .map(|it| it.collect())343 }344 }345}346347fn handle_control_flow_keywords(348 sema: &Semantics<'_, RootDatabase>,349 token: &SyntaxToken,350) -> Option<Vec<NavigationTarget>> {351 match token.kind() {352 // For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self,353 // so that VSCode will find the references when using `ctrl + click`354 T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),355 T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),356 T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {357 nav_for_break_points(sema, token)358 }359 T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),360 _ => None,361 }362}363364pub(crate) fn find_fn_or_blocks(365 sema: &Semantics<'_, RootDatabase>,366 token: &SyntaxToken,367) -> Vec<SyntaxNode> {368 let find_ancestors = |token: SyntaxToken| {369 let token_kind = token.kind();370371 for anc in sema.token_ancestors_with_macros(token) {372 let node = match_ast! {373 match anc {374 ast::Fn(fn_) => fn_.syntax().clone(),375 ast::ClosureExpr(c) => c.syntax().clone(),376 ast::BlockExpr(blk) => {377 match blk.modifier() {378 Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),379 Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),380 _ => continue,381 }382 },383 _ => continue,384 }385 };386387 return Some(node);388 }389 None390 };391392 sema.descend_into_macros(token.clone()).into_iter().filter_map(find_ancestors).collect_vec()393}394395fn nav_for_exit_points(396 sema: &Semantics<'_, RootDatabase>,397 token: &SyntaxToken,398) -> Option<Vec<NavigationTarget>> {399 let db = sema.db;400 let token_kind = token.kind();401402 let navs = find_fn_or_blocks(sema, token)403 .into_iter()404 .filter_map(|node| {405 let file_id = sema.hir_file_for(&node);406407 match_ast! {408 match node {409 ast::Fn(fn_) => {410 let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?;411 // For async token, we navigate to itself, which triggers412 // VSCode to find the references413 let focus_token = if matches!(token_kind, T![async]) {414 fn_.async_token()?415 } else {416 fn_.fn_token()?417 };418419 let focus_frange = InFile::new(file_id, focus_token.text_range())420 .original_node_file_range_opt(db)421 .map(|(frange, _)| frange);422423 if let Some(FileRange { file_id, range }) = focus_frange {424 let contains_frange = |nav: &NavigationTarget| {425 nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)426 };427428 if let Some(def_site) = nav.def_site.as_mut() {429 if contains_frange(def_site) {430 def_site.focus_range = Some(range);431 }432 } else if contains_frange(&nav.call_site) {433 nav.call_site.focus_range = Some(range);434 }435 }436437 Some(nav)438 },439 ast::ClosureExpr(c) => {440 let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range();441 let closure_in_file = InFile::new(file_id, c.into());442 Some(expr_to_nav(db, closure_in_file, Some(pipe_tok)))443 },444 ast::BlockExpr(blk) => {445 match blk.modifier() {446 Some(ast::BlockModifier::Async(_)) => {447 let async_tok = blk.async_token()?.text_range();448 let blk_in_file = InFile::new(file_id, blk.into());449 Some(expr_to_nav(db, blk_in_file, Some(async_tok)))450 },451 Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => {452 let try_tok = blk.try_block_modifier()?.try_token()?.text_range();453 let blk_in_file = InFile::new(file_id, blk.into());454 Some(expr_to_nav(db, blk_in_file, Some(try_tok)))455 },456 _ => None,457 }458 },459 _ => None,460 }461 }462 })463 .flatten()464 .collect_vec();465466 Some(navs)467}468469pub(crate) fn find_branch_root(470 sema: &Semantics<'_, RootDatabase>,471 token: &SyntaxToken,472) -> Vec<SyntaxNode> {473 let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {474 sema.descend_into_macros(token.clone())475 .into_iter()476 .filter_map(|token| node_filter(token.parent()?))477 .collect_vec()478 };479480 match token.kind() {481 T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),482 T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),483 T![if] => find_nodes(|node| {484 let if_expr = ast::IfExpr::cast(node)?;485486 let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {487 let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;488 let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {489 return None;490 };491492 (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)493 })494 .last()?;495496 Some(root_if.syntax().clone())497 }),498 _ => vec![],499 }500}501502fn nav_for_branch_exit_points(503 sema: &Semantics<'_, RootDatabase>,504 token: &SyntaxToken,505) -> Option<Vec<NavigationTarget>> {506 let db = sema.db;507508 let navs = match token.kind() {509 T![match] => find_branch_root(sema, token)510 .into_iter()511 .filter_map(|node| {512 let file_id = sema.hir_file_for(&node);513 let match_expr = ast::MatchExpr::cast(node)?;514 let focus_range = match_expr.match_token()?.text_range();515 let match_expr_in_file = InFile::new(file_id, match_expr.into());516 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))517 })518 .flatten()519 .collect_vec(),520521 T![=>] => find_branch_root(sema, token)522 .into_iter()523 .filter_map(|node| {524 let match_arm = ast::MatchArm::cast(node)?;525 let match_expr = sema526 .ancestors_with_macros(match_arm.syntax().clone())527 .find_map(ast::MatchExpr::cast)?;528 let file_id = sema.hir_file_for(match_expr.syntax());529 let focus_range = match_arm.fat_arrow_token()?.text_range();530 let match_expr_in_file = InFile::new(file_id, match_expr.into());531 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))532 })533 .flatten()534 .collect_vec(),535536 T![if] => find_branch_root(sema, token)537 .into_iter()538 .filter_map(|node| {539 let file_id = sema.hir_file_for(&node);540 let if_expr = ast::IfExpr::cast(node)?;541 let focus_range = if_expr.if_token()?.text_range();542 let if_expr_in_file = InFile::new(file_id, if_expr.into());543 Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))544 })545 .flatten()546 .collect_vec(),547548 _ => return Some(Vec::new()),549 };550551 Some(navs)552}553554fn nav_for_break_points(555 sema: &Semantics<'_, RootDatabase>,556 token: &SyntaxToken,557) -> Option<Vec<NavigationTarget>> {558 let db = sema.db;559560 let navs = find_loops(sema, token)?561 .filter_map(|expr| {562 let file_id = sema.hir_file_for(expr.syntax());563 let expr_in_file = InFile::new(file_id, expr.clone());564 let focus_range = match expr {565 ast::Expr::LoopExpr(loop_) => loop_.loop_token()?.text_range(),566 ast::Expr::WhileExpr(while_) => while_.while_token()?.text_range(),567 ast::Expr::ForExpr(for_) => for_.for_token()?.text_range(),568 // We guarantee that the label exists569 ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),570 _ => return None,571 };572 let nav = expr_to_nav(db, expr_in_file, Some(focus_range));573 Some(nav)574 })575 .flatten()576 .collect_vec();577578 Some(navs)579}580581fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec<NavigationTarget> {582 def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default()583}584585fn expr_to_nav(586 db: &RootDatabase,587 InFile { file_id, value }: InFile<ast::Expr>,588 focus_range: Option<TextRange>,589) -> UpmappingResult<NavigationTarget> {590 let kind = SymbolKind::Label;591592 let value_range = value.syntax().text_range();593 let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range);594 navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| {595 NavigationTarget::from_syntax(596 file_id,597 hir::Symbol::intern("<expr>"),598 focus_range,599 range,600 kind,601 )602 })603}604605#[cfg(test)]606mod tests {607 use crate::{GotoDefinitionConfig, fixture};608 use ide_db::{FileRange, ra_fixture::RaFixtureConfig};609 use itertools::Itertools;610611 const TEST_CONFIG: GotoDefinitionConfig<'_> =612 GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };613614 #[track_caller]615 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {616 let (analysis, position, expected) = fixture::annotations(ra_fixture);617 let navs = analysis618 .goto_definition(position, &TEST_CONFIG)619 .unwrap()620 .expect("no definition found")621 .info;622623 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());624 let navs = navs625 .into_iter()626 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })627 .sorted_by_key(cmp)628 .collect::<Vec<_>>();629 let expected = expected630 .into_iter()631 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })632 .sorted_by_key(cmp)633 .collect::<Vec<_>>();634635 assert_eq!(expected, navs);636 }637638 fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {639 let (analysis, position) = fixture::position(ra_fixture);640 let navs = analysis641 .goto_definition(position, &TEST_CONFIG)642 .unwrap()643 .expect("no definition found")644 .info;645646 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")647 }648649 fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {650 let (analysis, position, _) = fixture::annotations(ra_fixture);651 let navs = analysis652 .goto_definition(position, &TEST_CONFIG)653 .unwrap()654 .expect("no definition found")655 .info;656 assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());657 let Some(target) = navs.into_iter().next() else {658 panic!("expected single navigation target but encountered none");659 };660 assert_eq!(target.name, hir::Symbol::intern(expected_name));661 }662663 #[test]664 fn goto_def_pat_range_to_inclusive() {665 check_name(666 "RangeToInclusive",667 r#"668//- minicore: range669fn f(ch: char) -> bool {670 match ch {671 ..$0='z' => true,672 _ => false673 }674}675"#,676 );677 }678679 #[test]680 fn goto_def_pat_range_to() {681 check_name(682 "RangeTo",683 r#"684//- minicore: range685fn f(ch: char) -> bool {686 match ch {687 .$0.'z' => true,688 _ => false689 }690}691"#,692 );693 }694695 #[test]696 fn goto_def_pat_range() {697 check_name(698 "Range",699 r#"700//- minicore: range701fn f(ch: char) -> bool {702 match ch {703 'a'.$0.'z' => true,704 _ => false705 }706}707"#,708 );709 }710711 #[test]712 fn goto_def_pat_range_inclusive() {713 check_name(714 "RangeInclusive",715 r#"716//- minicore: range717fn f(ch: char) -> bool {718 match ch {719 'a'..$0='z' => true,720 _ => false721 }722}723"#,724 );725 }726727 #[test]728 fn goto_def_pat_range_from() {729 check_name(730 "RangeFrom",731 r#"732//- minicore: range733fn f(ch: char) -> bool {734 match ch {735 'a'..$0 => true,736 _ => false737 }738}739"#,740 );741 }742743 #[test]744 fn goto_def_expr_range() {745 check_name(746 "Range",747 r#"748//- minicore: range749let x = 0.$0.1;750"#,751 );752 }753754 #[test]755 fn goto_def_expr_range_from() {756 check_name(757 "RangeFrom",758 r#"759//- minicore: range760fn f(arr: &[i32]) -> &[i32] {761 &arr[0.$0.]762}763"#,764 );765 }766767 #[test]768 fn goto_def_expr_range_inclusive() {769 check_name(770 "RangeInclusive",771 r#"772//- minicore: range773let x = 0.$0.=1;774"#,775 );776 }777778 #[test]779 fn goto_def_expr_range_full() {780 check_name(781 "RangeFull",782 r#"783//- minicore: range784fn f(arr: &[i32]) -> &[i32] {785 &arr[.$0.]786}787"#,788 );789 }790791 #[test]792 fn goto_def_expr_range_to() {793 check_name(794 "RangeTo",795 r#"796//- minicore: range797fn f(arr: &[i32]) -> &[i32] {798 &arr[.$0.10]799}800"#,801 );802 }803804 #[test]805 fn goto_def_expr_range_to_inclusive() {806 check_name(807 "RangeToInclusive",808 r#"809//- minicore: range810fn f(arr: &[i32]) -> &[i32] {811 &arr[.$0.=10]812}813"#,814 );815 }816817 #[test]818 fn goto_def_in_included_file() {819 check(820 r#"821//- minicore:include822//- /main.rs823824include!("a.rs");825826fn main() {827 foo();828}829830//- /a.rs831fn func_in_include() {832 //^^^^^^^^^^^^^^^833}834835fn foo() {836 func_in_include$0();837}838"#,839 );840 }841842 #[test]843 fn goto_def_in_included_file_nested() {844 check(845 r#"846//- minicore:include847//- /main.rs848849macro_rules! passthrough {850 ($($tt:tt)*) => { $($tt)* }851}852853passthrough!(include!("a.rs"));854855fn main() {856 foo();857}858859//- /a.rs860fn func_in_include() {861 //^^^^^^^^^^^^^^^862}863864fn foo() {865 func_in_include$0();866}867"#,868 );869 }870871 #[test]872 fn goto_def_in_included_file_inside_mod() {873 check(874 r#"875//- minicore:include876//- /main.rs877mod a {878 include!("b.rs");879}880//- /b.rs881fn func_in_include() {882 //^^^^^^^^^^^^^^^883}884fn foo() {885 func_in_include$0();886}887"#,888 );889890 check(891 r#"892//- minicore:include893//- /main.rs894mod a {895 include!("a.rs");896}897//- /a.rs898fn func_in_include() {899 //^^^^^^^^^^^^^^^900}901902fn foo() {903 func_in_include$0();904}905"#,906 );907 }908909 #[test]910 fn goto_def_if_items_same_name() {911 check(912 r#"913trait Trait {914 type A;915 const A: i32;916 //^917}918919struct T;920impl Trait for T {921 type A = i32;922 const A$0: i32 = -9;923}"#,924 );925 }926 #[test]927 fn goto_def_in_mac_call_in_attr_invoc() {928 check(929 r#"930//- proc_macros: identity931pub struct Struct {932 // ^^^^^^933 field: i32,934}935936macro_rules! identity {937 ($($tt:tt)*) => {$($tt)*};938}939940#[proc_macros::identity]941fn function() {942 identity!(Struct$0 { field: 0 });943}944945"#,946 )947 }948949 #[test]950 fn goto_def_for_extern_crate() {951 check(952 r#"953//- /main.rs crate:main deps:std954extern crate std$0;955//- /std/lib.rs crate:std956// empty957//^file958"#,959 )960 }961962 #[test]963 fn goto_def_for_renamed_extern_crate() {964 check(965 r#"966//- /main.rs crate:main deps:std967extern crate std as abc$0;968//- /std/lib.rs crate:std969// empty970//^file971"#,972 )973 }974975 #[test]976 fn goto_def_in_items() {977 check(978 r#"979struct Foo;980 //^^^981enum E { X(Foo$0) }982"#,983 );984 }985986 #[test]987 fn goto_def_at_start_of_item() {988 check(989 r#"990struct Foo;991 //^^^992enum E { X($0Foo) }993"#,994 );995 }996997 #[test]998 fn goto_definition_resolves_correct_name() {999 check(1000 r#"1001//- /lib.rs1002use a::Foo;1003mod a;1004mod b;1005enum E { X(Foo$0) }10061007//- /a.rs1008pub struct Foo;1009 //^^^1010//- /b.rs1011pub struct Foo;1012"#,1013 );1014 }10151016 #[test]1017 fn goto_def_for_module_declaration() {1018 check(1019 r#"1020//- /lib.rs1021mod $0foo;10221023//- /foo.rs1024// empty1025//^file1026"#,1027 );10281029 check(1030 r#"1031//- /lib.rs1032mod $0foo;10331034//- /foo/mod.rs1035// empty1036//^file1037"#,1038 );1039 }10401041 #[test]1042 fn goto_def_for_macros() {1043 check(1044 r#"1045macro_rules! foo { () => { () } }1046 //^^^1047fn bar() {1048 $0foo!();1049}1050"#,1051 );1052 }10531054 #[test]1055 fn goto_def_for_macros_from_other_crates() {1056 check(1057 r#"1058//- /lib.rs crate:main deps:foo1059use foo::foo;1060fn bar() {1061 $0foo!();1062}10631064//- /foo/lib.rs crate:foo1065#[macro_export]1066macro_rules! foo { () => { () } }1067 //^^^1068"#,1069 );1070 }10711072 #[test]1073 fn goto_def_for_macros_in_use_tree() {1074 check(1075 r#"1076//- /lib.rs crate:main deps:foo1077use foo::foo$0;10781079//- /foo/lib.rs crate:foo1080#[macro_export]1081macro_rules! foo { () => { () } }1082 //^^^1083"#,1084 );1085 }10861087 #[test]1088 fn goto_def_for_macro_defined_fn_with_arg() {1089 check(1090 r#"1091//- /lib.rs1092macro_rules! define_fn {1093 ($name:ident) => (fn $name() {})1094}10951096define_fn!(foo);1097 //^^^10981099fn bar() {1100 $0foo();1101}1102"#,1103 );1104 }11051106 #[test]1107 fn goto_def_for_macro_defined_fn_no_arg() {1108 check(1109 r#"1110//- /lib.rs1111macro_rules! define_fn {1112 () => (fn foo() {})1113 //^^^1114}11151116 define_fn!();1117//^^^^^^^^^^1118fn bar() {1119 $0foo();1120}1121"#,1122 );1123 }11241125 #[test]1126 fn goto_definition_works_for_macro_inside_pattern() {1127 check(1128 r#"1129//- /lib.rs1130macro_rules! foo {() => {0}}1131 //^^^11321133fn bar() {1134 match (0,1) {1135 ($0foo!(), _) => {}1136 }1137}1138"#,1139 );1140 }11411142 #[test]1143 fn goto_definition_works_for_macro_inside_match_arm_lhs() {1144 check(1145 r#"1146//- /lib.rs1147macro_rules! foo {() => {0}}1148 //^^^1149fn bar() {1150 match 0 {1151 $0foo!() => {}1152 }1153}1154"#,1155 );1156 }11571158 #[test]1159 fn goto_definition_works_for_consts_inside_range_pattern() {1160 check(1161 r#"1162//- /lib.rs1163const A: u32 = 0;1164 //^11651166fn bar(v: u32) {1167 match v {1168 0..=$0A => {}1169 _ => {}1170 }1171}1172"#,1173 );1174 }11751176 #[test]1177 fn goto_def_for_use_alias() {1178 check(1179 r#"1180//- /lib.rs crate:main deps:foo1181use foo as bar$0;11821183//- /foo/lib.rs crate:foo1184// empty1185//^file1186"#,1187 );1188 }11891190 #[test]1191 fn goto_def_for_use_alias_foo_macro() {1192 check(1193 r#"1194//- /lib.rs crate:main deps:foo1195use foo::foo as bar$0;11961197//- /foo/lib.rs crate:foo1198#[macro_export]1199macro_rules! foo { () => { () } }1200 //^^^1201"#,1202 );1203 }12041205 #[test]1206 fn goto_def_for_methods() {1207 check(1208 r#"1209struct Foo;1210impl Foo {1211 fn frobnicate(&self) { }1212 //^^^^^^^^^^1213}12141215fn bar(foo: &Foo) {1216 foo.frobnicate$0();1217}1218"#,1219 );1220 }12211222 #[test]1223 fn goto_def_for_fields() {1224 check(1225 r#"1226struct Foo {1227 spam: u32,1228} //^^^^12291230fn bar(foo: &Foo) {1231 foo.spam$0;1232}1233"#,1234 );1235 }12361237 #[test]1238 fn goto_def_for_record_fields() {1239 check(1240 r#"1241//- /lib.rs1242struct Foo {1243 spam: u32,1244} //^^^^12451246fn bar() -> Foo {1247 Foo {1248 spam$0: 0,1249 }1250}1251"#,1252 );1253 }12541255 #[test]1256 fn goto_def_for_record_pat_fields() {1257 check(1258 r#"1259//- /lib.rs1260struct Foo {1261 spam: u32,1262} //^^^^12631264fn bar(foo: Foo) -> Foo {1265 let Foo { spam$0: _, } = foo1266}1267"#,1268 );1269 }12701271 #[test]1272 fn goto_def_for_record_fields_macros() {1273 check(1274 r"1275macro_rules! m { () => { 92 };}1276struct Foo { spam: u32 }1277 //^^^^12781279fn bar() -> Foo {1280 Foo { spam$0: m!() }1281}1282",1283 );1284 }12851286 #[test]1287 fn goto_for_tuple_fields() {1288 check(1289 r#"1290struct Foo(u32);1291 //^^^12921293fn bar() {1294 let foo = Foo(0);1295 foo.$00;1296}1297"#,1298 );1299 }13001301 #[test]1302 fn goto_def_for_ufcs_inherent_methods() {1303 check(1304 r#"1305struct Foo;1306impl Foo {1307 fn frobnicate() { }1308} //^^^^^^^^^^13091310fn bar(foo: &Foo) {1311 Foo::frobnicate$0();1312}1313"#,1314 );1315 }13161317 #[test]1318 fn goto_def_for_ufcs_trait_methods_through_traits() {1319 check(1320 r#"1321trait Foo {1322 fn frobnicate();1323} //^^^^^^^^^^13241325fn bar() {1326 Foo::frobnicate$0();1327}1328"#,1329 );1330 }13311332 #[test]1333 fn goto_def_for_ufcs_trait_methods_through_self() {1334 check(1335 r#"1336struct Foo;1337trait Trait {1338 fn frobnicate();1339} //^^^^^^^^^^1340impl Trait for Foo {}13411342fn bar() {1343 Foo::frobnicate$0();1344}1345"#,1346 );1347 }13481349 #[test]1350 fn goto_definition_on_self() {1351 check(1352 r#"1353struct Foo;1354impl Foo {1355 //^^^1356 pub fn new() -> Self {1357 Self$0 {}1358 }1359}1360"#,1361 );1362 check(1363 r#"1364struct Foo;1365impl Foo {1366 //^^^1367 pub fn new() -> Self$0 {1368 Self {}1369 }1370}1371"#,1372 );13731374 check(1375 r#"1376enum Foo { A }1377impl Foo {1378 //^^^1379 pub fn new() -> Self$0 {1380 Foo::A1381 }1382}1383"#,1384 );13851386 check(1387 r#"1388enum Foo { A }1389impl Foo {1390 //^^^1391 pub fn thing(a: &Self$0) {1392 }1393}1394"#,1395 );1396 }13971398 #[test]1399 fn goto_definition_on_self_in_trait_impl() {1400 check(1401 r#"1402struct Foo;1403trait Make {1404 fn new() -> Self;1405}1406impl Make for Foo {1407 //^^^1408 fn new() -> Self {1409 Self$0 {}1410 }1411}1412"#,1413 );14141415 check(1416 r#"1417struct Foo;1418trait Make {1419 fn new() -> Self;1420}1421impl Make for Foo {1422 //^^^1423 fn new() -> Self$0 {1424 Self {}1425 }1426}1427"#,1428 );1429 }14301431 #[test]1432 fn goto_def_when_used_on_definition_name_itself() {1433 check(1434 r#"1435struct Foo$0 { value: u32 }1436 //^^^1437 "#,1438 );14391440 check(1441 r#"1442struct Foo {1443 field$0: string,1444} //^^^^^1445"#,1446 );14471448 check(1449 r#"1450fn foo_test$0() { }1451 //^^^^^^^^1452"#,1453 );14541455 check(1456 r#"1457enum Foo$0 { Variant }1458 //^^^1459"#,1460 );14611462 check(1463 r#"1464enum Foo {1465 Variant1,1466 Variant2$0,1467 //^^^^^^^^1468 Variant3,1469}1470"#,1471 );14721473 check(1474 r#"1475static INNER$0: &str = "";1476 //^^^^^1477"#,1478 );14791480 check(1481 r#"1482const INNER$0: &str = "";1483 //^^^^^1484"#,1485 );14861487 check(1488 r#"1489type Thing$0 = Option<()>;1490 //^^^^^1491"#,1492 );14931494 check(1495 r#"1496trait Foo$0 { }1497 //^^^1498"#,1499 );15001501 check(1502 r#"1503trait Foo$0 = ;1504 //^^^1505"#,1506 );15071508 check(1509 r#"1510mod bar$0 { }1511 //^^^1512"#,1513 );1514 }15151516 #[test]1517 fn goto_from_macro() {1518 check(1519 r#"1520macro_rules! id {1521 ($($tt:tt)*) => { $($tt)* }1522}1523fn foo() {}1524 //^^^1525id! {1526 fn bar() {1527 fo$0o();1528 }1529}1530mod confuse_index { fn foo(); }1531"#,1532 );1533 }15341535 #[test]1536 fn goto_through_format() {1537 check(1538 r#"1539//- minicore: fmt1540#[macro_export]1541macro_rules! format {1542 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))1543}1544pub mod __export {1545 pub use core::format_args;1546 fn foo() {} // for index confusion1547}1548fn foo() -> i8 {}1549 //^^^1550fn test() {1551 format!("{}", fo$0o())1552}1553"#,1554 );1555 }15561557 #[test]1558 fn goto_through_included_file() {1559 check(1560 r#"1561//- /main.rs1562#[rustc_builtin_macro]1563macro_rules! include {}15641565include!("foo.rs");15661567fn f() {1568 foo$0();1569}15701571mod confuse_index {1572 pub fn foo() {}1573}15741575//- /foo.rs1576fn foo() {}1577 //^^^1578 "#,1579 );1580 }15811582 #[test]1583 fn goto_through_included_file_struct_with_doc_comment() {1584 check(1585 r#"1586//- /main.rs1587#[rustc_builtin_macro]1588macro_rules! include {}15891590include!("foo.rs");15911592fn f() {1593 let x = Foo$0;1594}15951596mod confuse_index {1597 pub struct Foo;1598}15991600//- /foo.rs1601/// This is a doc comment1602pub struct Foo;1603 //^^^1604 "#,1605 );1606 }16071608 #[test]1609 fn goto_for_type_param() {1610 check(1611 r#"1612struct Foo<T: Clone> { t: $0T }1613 //^1614"#,1615 );1616 }16171618 #[test]1619 fn goto_within_macro() {1620 check(1621 r#"1622macro_rules! id {1623 ($($tt:tt)*) => ($($tt)*)1624}16251626fn foo() {1627 let x = 1;1628 //^1629 id!({1630 let y = $0x;1631 let z = y;1632 });1633}1634"#,1635 );16361637 check(1638 r#"1639macro_rules! id {1640 ($($tt:tt)*) => ($($tt)*)1641}16421643fn foo() {1644 let x = 1;1645 id!({1646 let y = x;1647 //^1648 let z = $0y;1649 });1650}1651"#,1652 );1653 }16541655 #[test]1656 fn goto_def_in_local_fn() {1657 check(1658 r#"1659fn main() {1660 fn foo() {1661 let x = 92;1662 //^1663 $0x;1664 }1665}1666"#,1667 );1668 }16691670 #[test]1671 fn goto_def_in_local_macro() {1672 check(1673 r#"1674fn bar() {1675 macro_rules! foo { () => { () } }1676 //^^^1677 $0foo!();1678}1679"#,1680 );1681 }16821683 #[test]1684 fn goto_def_for_field_init_shorthand() {1685 check(1686 r#"1687struct Foo { x: i32 }1688 //^1689fn main() {1690 let x = 92;1691 //^1692 Foo { x$0 };1693}1694"#,1695 )1696 }16971698 #[test]1699 fn goto_def_for_enum_variant_field() {1700 check(1701 r#"1702enum Foo {1703 Bar { x: i32 }1704 //^1705}1706fn baz(foo: Foo) {1707 match foo {1708 Foo::Bar { x$0 } => x1709 //^1710 };1711}1712"#,1713 );1714 }17151716 #[test]1717 fn goto_def_for_enum_variant_self_pattern_const() {1718 check(1719 r#"1720enum Foo { Bar }1721 //^^^1722impl Foo {1723 fn baz(self) {1724 match self { Self::Bar$0 => {} }1725 }1726}1727"#,1728 );1729 }17301731 #[test]1732 fn goto_def_for_enum_variant_self_pattern_record() {1733 check(1734 r#"1735enum Foo { Bar { val: i32 } }1736 //^^^1737impl Foo {1738 fn baz(self) -> i32 {1739 match self { Self::Bar$0 { val } => {} }1740 }1741}1742"#,1743 );1744 }17451746 #[test]1747 fn goto_def_for_enum_variant_self_expr_const() {1748 check(1749 r#"1750enum Foo { Bar }1751 //^^^1752impl Foo {1753 fn baz(self) { Self::Bar$0; }1754}1755"#,1756 );1757 }17581759 #[test]1760 fn goto_def_for_enum_variant_self_expr_record() {1761 check(1762 r#"1763enum Foo { Bar { val: i32 } }1764 //^^^1765impl Foo {1766 fn baz(self) { Self::Bar$0 {val: 4}; }1767}1768"#,1769 );1770 }17711772 #[test]1773 fn goto_def_for_type_alias_generic_parameter() {1774 check(1775 r#"1776type Alias<T> = T$0;1777 //^1778"#,1779 )1780 }17811782 #[test]1783 fn goto_def_for_macro_container() {1784 check(1785 r#"1786//- /lib.rs crate:main deps:foo1787foo::module$0::mac!();17881789//- /foo/lib.rs crate:foo1790pub mod module {1791 //^^^^^^1792 #[macro_export]1793 macro_rules! _mac { () => { () } }1794 pub use crate::_mac as mac;1795}1796"#,1797 );1798 }17991800 #[test]1801 fn goto_def_for_assoc_ty_in_path() {1802 check(1803 r#"1804trait Iterator {1805 type Item;1806 //^^^^1807}18081809fn f() -> impl Iterator<Item$0 = u8> {}1810"#,1811 );1812 }18131814 #[test]1815 fn goto_def_for_super_assoc_ty_in_path() {1816 check(1817 r#"1818trait Super {1819 type Item;1820 //^^^^1821}18221823trait Sub: Super {}18241825fn f() -> impl Sub<Item$0 = u8> {}1826"#,1827 );1828 }18291830 #[test]1831 fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {1832 check(1833 r#"1834mod bar {1835 pub struct Foo {}1836 //^^^1837 pub fn Foo() {}1838}18391840fn baz() {1841 let _foo_enum: bar::Foo$0 = bar::Foo {};1842}1843 "#,1844 )1845 }18461847 #[test]1848 fn unknown_assoc_ty() {1849 check_unresolved(1850 r#"1851trait Iterator { type Item; }1852fn f() -> impl Iterator<Invalid$0 = u8> {}1853"#,1854 )1855 }18561857 #[test]1858 fn goto_def_for_assoc_ty_in_path_multiple() {1859 check(1860 r#"1861trait Iterator {1862 type A;1863 //^1864 type B;1865}18661867fn f() -> impl Iterator<A$0 = u8, B = ()> {}1868"#,1869 );1870 check(1871 r#"1872trait Iterator {1873 type A;1874 type B;1875 //^1876}18771878fn f() -> impl Iterator<A = u8, B$0 = ()> {}1879"#,1880 );1881 }18821883 #[test]1884 fn goto_def_for_assoc_ty_ufcs() {1885 check(1886 r#"1887trait Iterator {1888 type Item;1889 //^^^^1890}18911892fn g() -> <() as Iterator<Item$0 = ()>>::Item {}1893"#,1894 );1895 }18961897 #[test]1898 fn goto_def_for_assoc_ty_ufcs_multiple() {1899 check(1900 r#"1901trait Iterator {1902 type A;1903 //^1904 type B;1905}19061907fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}1908"#,1909 );1910 check(1911 r#"1912trait Iterator {1913 type A;1914 type B;1915 //^1916}19171918fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}1919"#,1920 );1921 }19221923 #[test]1924 fn goto_self_param_ty_specified() {1925 check(1926 r#"1927struct Foo {}19281929impl Foo {1930 fn bar(self: &Foo) {1931 //^^^^1932 let foo = sel$0f;1933 }1934}"#,1935 )1936 }19371938 #[test]1939 fn goto_self_param_on_decl() {1940 check(1941 r#"1942struct Foo {}19431944impl Foo {1945 fn bar(&self$0) {1946 //^^^^1947 }1948}"#,1949 )1950 }19511952 #[test]1953 fn goto_lifetime_param_on_decl() {1954 check(1955 r#"1956fn foo<'foobar$0>(_: &'foobar ()) {1957 //^^^^^^^1958}"#,1959 )1960 }19611962 #[test]1963 fn goto_lifetime_param_decl() {1964 check(1965 r#"1966fn foo<'foobar>(_: &'foobar$0 ()) {1967 //^^^^^^^1968}"#,1969 )1970 }19711972 #[test]1973 fn goto_lifetime_param_decl_nested() {1974 check(1975 r#"1976fn foo<'foobar>(_: &'foobar ()) {1977 fn foo<'foobar>(_: &'foobar$0 ()) {}1978 //^^^^^^^1979}"#,1980 )1981 }19821983 #[test]1984 fn goto_lifetime_hrtb() {1985 // FIXME: requires the HIR to somehow track these hrtb lifetimes1986 check_unresolved(1987 r#"1988trait Foo<T> {}1989fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}1990 //^^1991"#,1992 );1993 check_unresolved(1994 r#"1995trait Foo<T> {}1996fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}1997 //^^1998"#,1999 );2000 }
Code quality findings 47
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
.unwrap()
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning
correctness
expect-usage
.expect("no definition found")
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning
correctness
unwrap-usage
.unwrap()
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning
correctness
expect-usage
.expect("no definition found")
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
&arr[0.$0.]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
&arr[.$0.]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
&arr[.$0.10]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
&arr[.$0.=10]
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
/// You might want to see [`std::fs::read()`] too.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
/// Gives you a [`TheItem$0`].
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
Struct[0]$0;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning
correctness
unchecked-indexing
foo[0]$0 = Bar;
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning
correctness
discarded-result
let _ = core::mem::offset_of!(Foo, fiel$0d);
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning
correctness
discarded-result
let _ = core::mem::offset_of!(Bar, 0.fiel$0d);
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning
correctness
discarded-result
let _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d);
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning
correctness
discarded-result
let _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field);
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match token.kind() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match anc {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
ast::Fn(fn_) => fn_.syntax().clone(),
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
ast::ClosureExpr(c) => c.syntax().clone(),
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match blk.modifier() {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info
performance
clone-in-loop
Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
let focus_range = match expr {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match ch {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match ch {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match ch {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match ch {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match ch {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match v {
Info: This standard library function returns a Result. Ensure the Result is handled properly (e.g., using '?', match, if let) rather than potentially panicking with .unwrap() or .expect().
info
correctness
unhandled-result
/// You might want to see [`std::fs::read()`] too.
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info
maintainability
include-in-binary
let str = include_str!("foo.txt$0");
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info
maintainability
include-in-binary
let str = include_str!(concat!("foo", ".tx$0t"));
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info
maintainability
include-in-binary
#[doc = include_str!("docs.md$0")]
Info: Direct printing to stdout/stderr. For application logging, prefer using a logging facade like `log` or `tracing` for better control over levels, formatting, and output destinations.
info
maintainability
println-macro
println!("{}", i);
Info: Direct printing to stdout/stderr. For application logging, prefer using a logging facade like `log` or `tracing` for better control over levels, formatting, and output destinations.
info
maintainability
println-macro
println!("{}", i);
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match 0 {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match 0 {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match 0 {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match 42 {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match Tag(Path) {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match x {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match x {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info
correctness
match-wildcard
match x {