1use std::{iter, mem::discriminant};
2
3use 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::{MiniCore, ra_fixture::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};
20use itertools::Itertools;
21use span::{Edition, FileId};
22use syntax::{
23 AstNode, AstToken,
24 SyntaxKind::*,
25 SyntaxNode, SyntaxToken, T, TextRange,
26 ast::{self, HasLoopBody},
27 match_ast,
28};
29
30#[derive(Debug)]
31pub struct GotoDefinitionConfig<'a> {
32 pub minicore: MiniCore<'a>,
33}
34
35pub(crate) fn goto_definition(
47 db: &RootDatabase,
48 FilePosition { file_id, offset }: FilePosition,
49 config: &GotoDefinitionConfig<'_>,
50) -> Option<RangeInfo<Vec<NavigationTarget>>> {
51 let sema = &Semantics::new(db);
52 let file = sema.parse_guess_edition(file_id).syntax().clone();
53 let edition =
54 sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
55 let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
56 IDENT
57 | INT_NUMBER
58 | LIFETIME_IDENT
59 | T![self]
60 | T![super]
61 | T![crate]
62 | T![Self]
63 | COMMENT => 4,
64 T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
66 kind if kind.is_keyword(edition) => 2,
67 T!['('] | T![')'] => 2,
68 kind if kind.is_trivia() => 0,
69 _ => 1,
70 })?;
71 if let Some(doc_comment) = token_as_doc_comment(&original_token) {
72 return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {
73 let nav = def.try_to_nav(sema)?;
74 Some(RangeInfo::new(link_range, nav.collect()))
75 });
76 }
77
78 if let Some((range, _, _, resolution)) =
79 sema.check_for_format_args_template(original_token.clone(), offset)
80 {
81 return Some(RangeInfo::new(
82 range,
83 match resolution {
84 Some(res) => def_to_nav(sema, Definition::from(res)),
85 None => vec![],
86 },
87 ));
88 }
89
90 if let Some(navs) = handle_control_flow_keywords(sema, &original_token) {
91 return Some(RangeInfo::new(original_token.text_range(), navs));
92 }
93
94 let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
95 let mut navs = Vec::new();
96 for token in tokens {
97 if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
98 navs.extend(n);
99 continue;
100 }
101
102 if let Some(token) = ast::String::cast(token.value.clone())
103 && let Some(original_token) = ast::String::cast(original_token.clone())
104 && let Some((analysis, fixture_analysis)) =
105 Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
106 && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
107 {
108 return hir::attach_db_allow_change(&analysis.db, || {
109 goto_definition(
110 &analysis.db,
111 FilePosition { file_id: virtual_file_id, offset: file_offset },
112 config,
113 )
114 })
115 .and_then(|navs| {
116 navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()
117 });
118 }
119
120 let parent = token.value.parent()?;
121
122 let token_file_id = token.file_id;
123 if let Some(token) = ast::String::cast(token.value.clone())
124 && let Some(x) =
125 try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
126 {
127 navs.push(x);
128 continue;
129 }
130
131 if ast::TokenTree::can_cast(parent.kind())
132 && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
133 {
134 navs.push(x);
135 continue;
136 }
137
138 let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };
139 navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {
140 if let Definition::ExternCrateDecl(crate_def) = def {
141 return crate_def
142 .resolved_crate(db)
143 .map(|it| it.root_module().to_nav(sema.db))
144 .into_iter()
145 .flatten()
146 .collect();
147 }
148 try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))
149 }));
150 }
151 let navs = navs.into_iter().unique().collect();
152
153 Some(RangeInfo::new(original_token.text_range(), navs))
154}
155
156fn find_definition_for_known_blanket_dual_impls(
158 sema: &Semantics<'_, RootDatabase>,
159 original_token: &SyntaxToken,
160) -> Option<Vec<NavigationTarget>> {
161 let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
162 let callable = sema.resolve_method_call_as_callable(&method_call)?;
163 let CallableKind::Function(f) = callable.kind() else { return None };
164 let assoc = f.as_assoc_item(sema.db)?;
165
166 let return_type = callable.return_type();
167 let fd = FamousDefs(sema, return_type.krate(sema.db));
168
169 let t = match assoc.container(sema.db) {
170 hir::AssocItemContainer::Trait(t) => t,
171 hir::AssocItemContainer::Impl(impl_)
172 if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
173 {
174 let t = fd.core_convert_FromStr()?;
175 let t_f = t.function(sema.db, &sym::from_str)?;
176 return sema
177 .resolve_trait_impl_method(
178 return_type.clone(),
179 t,
180 t_f,
181 [return_type.type_arguments().next()?],
182 )
183 .map(|f| def_to_nav(sema, f.into()));
184 }
185 hir::AssocItemContainer::Impl(_) => return None,
186 };
187
188 let fn_name = f.name(sema.db);
189 let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
190 let dual = fd.core_convert_From()?;
191 let dual_f = dual.function(sema.db, &sym::from)?;
192 sema.resolve_trait_impl_method(
193 return_type.clone(),
194 dual,
195 dual_f,
196 [return_type, callable.receiver_param(sema.db)?.1],
197 )?
198 } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
199 let dual = fd.core_convert_TryFrom()?;
200 let dual_f = dual.function(sema.db, &sym::try_from)?;
201 sema.resolve_trait_impl_method(
202 return_type.clone(),
203 dual,
204 dual_f,
205 [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
207 )?
208 } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {
209 let dual = fd.core_fmt_Display()?;
210 let dual_f = dual.function(sema.db, &sym::fmt)?;
211 sema.resolve_trait_impl_method(
212 return_type.clone(),
213 dual,
214 dual_f,
215 [callable.receiver_param(sema.db)?.1.strip_reference()],
216 )?
217 } else {
218 return None;
219 };
220 let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
223 let def = Definition::from(f);
224 Some(def_to_nav(sema, def))
225}
226
227fn try_lookup_include_path(
228 sema: &Semantics<'_, RootDatabase>,
229 token: InFile<ast::String>,
230 file_id: FileId,
231) -> Option<NavigationTarget> {
232 let file = token.file_id.macro_file()?;
233
234 if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())
237 .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())
238 {
239 return None;
240 }
241 let path = token.value.value().ok()?;
242
243 let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
244 let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;
245 Some(NavigationTarget {
246 file_id,
247 full_range: TextRange::new(0.into(), size),
248 name: path.into(),
249 alias: None,
250 focus_range: None,
251 kind: None,
252 container_name: None,
253 description: None,
254 docs: None,
255 })
256}
257
258fn try_lookup_macro_def_in_macro_use(
259 sema: &Semantics<'_, RootDatabase>,
260 token: SyntaxToken,
261) -> Option<NavigationTarget> {
262 let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?;
263 let extern_crate = sema.to_def(&extern_crate)?;
264 let krate = extern_crate.resolved_crate(sema.db)?;
265
266 for mod_def in krate.root_module().declarations(sema.db) {
267 if let ModuleDef::Macro(mac) = mod_def
268 && mac.name(sema.db).as_str() == token.text()
269 && let Some(nav) = mac.try_to_nav(sema)
270 {
271 return Some(nav.call_site);
272 }
273 }
274
275 None
276}
277
278fn try_filter_trait_item_definition(
286 sema: &Semantics<'_, RootDatabase>,
287 def: &Definition,
288) -> Option<Vec<NavigationTarget>> {
289 let db = sema.db;
290 let assoc = def.as_assoc_item(db)?;
291 match assoc {
292 AssocItem::Function(..) => None,
293 AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
294 let trait_ = assoc.implemented_trait(db)?;
295 let name = def.name(db)?;
296 let discriminant_value = discriminant(&assoc);
297 trait_
298 .items(db)
299 .iter()
300 .filter(|itm| discriminant(*itm) == discriminant_value)
301 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten())
302 .map(|it| it.collect())
303 }
304 }
305}
306
307fn handle_control_flow_keywords(
308 sema: &Semantics<'_, RootDatabase>,
309 token: &SyntaxToken,
310) -> Option<Vec<NavigationTarget>> {
311 match token.kind() {
312 T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),
315 T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),
316 T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {
317 nav_for_break_points(sema, token)
318 }
319 T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),
320 _ => None,
321 }
322}
323
324pub(crate) fn find_fn_or_blocks(
325 sema: &Semantics<'_, RootDatabase>,
326 token: &SyntaxToken,
327) -> Vec<SyntaxNode> {
328 let find_ancestors = |token: SyntaxToken| {
329 let token_kind = token.kind();
330
331 for anc in sema.token_ancestors_with_macros(token) {
332 let node = match_ast! {
333 match anc {
334 ast::Fn(fn_) => fn_.syntax().clone(),
335 ast::ClosureExpr(c) => c.syntax().clone(),
336 ast::BlockExpr(blk) => {
337 match blk.modifier() {
338 Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),
339 Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => blk.syntax().clone(),
340 _ => continue,
341 }
342 },
343 _ => continue,
344 }
345 };
346
347 return Some(node);
348 }
349 None
350 };
351
352 sema.descend_into_macros(token.clone()).into_iter().filter_map(find_ancestors).collect_vec()
353}
354
355fn nav_for_exit_points(
356 sema: &Semantics<'_, RootDatabase>,
357 token: &SyntaxToken,
358) -> Option<Vec<NavigationTarget>> {
359 let db = sema.db;
360 let token_kind = token.kind();
361
362 let navs = find_fn_or_blocks(sema, token)
363 .into_iter()
364 .filter_map(|node| {
365 let file_id = sema.hir_file_for(&node);
366
367 match_ast! {
368 match node {
369 ast::Fn(fn_) => {
370 let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?;
371 let focus_token = if matches!(token_kind, T![async]) {
374 fn_.async_token()?
375 } else {
376 fn_.fn_token()?
377 };
378
379 let focus_frange = InFile::new(file_id, focus_token.text_range())
380 .original_node_file_range_opt(db)
381 .map(|(frange, _)| frange);
382
383 if let Some(FileRange { file_id, range }) = focus_frange {
384 let contains_frange = |nav: &NavigationTarget| {
385 nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)
386 };
387
388 if let Some(def_site) = nav.def_site.as_mut() {
389 if contains_frange(def_site) {
390 def_site.focus_range = Some(range);
391 }
392 } else if contains_frange(&nav.call_site) {
393 nav.call_site.focus_range = Some(range);
394 }
395 }
396
397 Some(nav)
398 },
399 ast::ClosureExpr(c) => {
400 let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range();
401 let closure_in_file = InFile::new(file_id, c.into());
402 Some(expr_to_nav(db, closure_in_file, Some(pipe_tok)))
403 },
404 ast::BlockExpr(blk) => {
405 match blk.modifier() {
406 Some(ast::BlockModifier::Async(_)) => {
407 let async_tok = blk.async_token()?.text_range();
408 let blk_in_file = InFile::new(file_id, blk.into());
409 Some(expr_to_nav(db, blk_in_file, Some(async_tok)))
410 },
411 Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => {
412 let try_tok = blk.try_token()?.text_range();
413 let blk_in_file = InFile::new(file_id, blk.into());
414 Some(expr_to_nav(db, blk_in_file, Some(try_tok)))
415 },
416 _ => None,
417 }
418 },
419 _ => None,
420 }
421 }
422 })
423 .flatten()
424 .collect_vec();
425
426 Some(navs)
427}
428
429pub(crate) fn find_branch_root(
430 sema: &Semantics<'_, RootDatabase>,
431 token: &SyntaxToken,
432) -> Vec<SyntaxNode> {
433 let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {
434 sema.descend_into_macros(token.clone())
435 .into_iter()
436 .filter_map(|token| node_filter(token.parent()?))
437 .collect_vec()
438 };
439
440 match token.kind() {
441 T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),
442 T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),
443 T![if] => find_nodes(|node| {
444 let if_expr = ast::IfExpr::cast(node)?;
445
446 let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {
447 let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;
448 let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {
449 return None;
450 };
451
452 (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)
453 })
454 .last()?;
455
456 Some(root_if.syntax().clone())
457 }),
458 _ => vec![],
459 }
460}
461
462fn nav_for_branch_exit_points(
463 sema: &Semantics<'_, RootDatabase>,
464 token: &SyntaxToken,
465) -> Option<Vec<NavigationTarget>> {
466 let db = sema.db;
467
468 let navs = match token.kind() {
469 T![match] => find_branch_root(sema, token)
470 .into_iter()
471 .filter_map(|node| {
472 let file_id = sema.hir_file_for(&node);
473 let match_expr = ast::MatchExpr::cast(node)?;
474 let focus_range = match_expr.match_token()?.text_range();
475 let match_expr_in_file = InFile::new(file_id, match_expr.into());
476 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
477 })
478 .flatten()
479 .collect_vec(),
480
481 T![=>] => find_branch_root(sema, token)
482 .into_iter()
483 .filter_map(|node| {
484 let match_arm = ast::MatchArm::cast(node)?;
485 let match_expr = sema
486 .ancestors_with_macros(match_arm.syntax().clone())
487 .find_map(ast::MatchExpr::cast)?;
488 let file_id = sema.hir_file_for(match_expr.syntax());
489 let focus_range = match_arm.fat_arrow_token()?.text_range();
490 let match_expr_in_file = InFile::new(file_id, match_expr.into());
491 Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))
492 })
493 .flatten()
494 .collect_vec(),
495
496 T![if] => find_branch_root(sema, token)
497 .into_iter()
498 .filter_map(|node| {
499 let file_id = sema.hir_file_for(&node);
500 let if_expr = ast::IfExpr::cast(node)?;
501 let focus_range = if_expr.if_token()?.text_range();
502 let if_expr_in_file = InFile::new(file_id, if_expr.into());
503 Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))
504 })
505 .flatten()
506 .collect_vec(),
507
508 _ => return Some(Vec::new()),
509 };
510
511 Some(navs)
512}
513
514pub(crate) fn find_loops(
515 sema: &Semantics<'_, RootDatabase>,
516 token: &SyntaxToken,
517) -> Option<Vec<ast::Expr>> {
518 let parent = token.parent()?;
519 let lbl = match_ast! {
520 match parent {
521 ast::BreakExpr(break_) => break_.lifetime(),
522 ast::ContinueExpr(continue_) => continue_.lifetime(),
523 _ => None,
524 }
525 };
526 let label_matches =
527 |it: Option<ast::Label>| match (lbl.as_ref(), it.and_then(|it| it.lifetime())) {
528 (Some(lbl), Some(it)) => lbl.text() == it.text(),
529 (None, _) => true,
530 (Some(_), None) => false,
531 };
532
533 let find_ancestors = |token: SyntaxToken| {
534 for anc in sema.token_ancestors_with_macros(token).filter_map(ast::Expr::cast) {
535 let node = match &anc {
536 ast::Expr::LoopExpr(loop_) if label_matches(loop_.label()) => anc,
537 ast::Expr::WhileExpr(while_) if label_matches(while_.label()) => anc,
538 ast::Expr::ForExpr(for_) if label_matches(for_.label()) => anc,
539 ast::Expr::BlockExpr(blk)
540 if blk.label().is_some() && label_matches(blk.label()) =>
541 {
542 anc
543 }
544 _ => continue,
545 };
546
547 return Some(node);
548 }
549 None
550 };
551
552 sema.descend_into_macros(token.clone())
553 .into_iter()
554 .filter_map(find_ancestors)
555 .collect_vec()
556 .into()
557}
558
559fn nav_for_break_points(
560 sema: &Semantics<'_, RootDatabase>,
561 token: &SyntaxToken,
562) -> Option<Vec<NavigationTarget>> {
563 let db = sema.db;
564
565 let navs = find_loops(sema, token)?
566 .into_iter()
567 .filter_map(|expr| {
568 let file_id = sema.hir_file_for(expr.syntax());
569 let expr_in_file = InFile::new(file_id, expr.clone());
570 let focus_range = match expr {
571 ast::Expr::LoopExpr(loop_) => loop_.loop_token()?.text_range(),
572 ast::Expr::WhileExpr(while_) => while_.while_token()?.text_range(),
573 ast::Expr::ForExpr(for_) => for_.for_token()?.text_range(),
574 ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),
576 _ => return None,
577 };
578 let nav = expr_to_nav(db, expr_in_file, Some(focus_range));
579 Some(nav)
580 })
581 .flatten()
582 .collect_vec();
583
584 Some(navs)
585}
586
587fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition) -> Vec<NavigationTarget> {
588 def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default()
589}
590
591fn expr_to_nav(
592 db: &RootDatabase,
593 InFile { file_id, value }: InFile<ast::Expr>,
594 focus_range: Option<TextRange>,
595) -> UpmappingResult<NavigationTarget> {
596 let kind = SymbolKind::Label;
597
598 let value_range = value.syntax().text_range();
599 let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range);
600 navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| {
601 NavigationTarget::from_syntax(file_id, "<expr>".into(), focus_range, range, kind)
602 })
603}
604
605#[cfg(test)]
606mod tests {
607 use crate::{GotoDefinitionConfig, fixture};
608 use ide_db::{FileRange, MiniCore};
609 use itertools::Itertools;
610 use syntax::SmolStr;
611
612 const TEST_CONFIG: GotoDefinitionConfig<'_> =
613 GotoDefinitionConfig { minicore: MiniCore::default() };
614
615 #[track_caller]
616 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
617 let (analysis, position, expected) = fixture::annotations(ra_fixture);
618 let navs = analysis
619 .goto_definition(position, &TEST_CONFIG)
620 .unwrap()
621 .expect("no definition found")
622 .info;
623
624 let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
625 let navs = navs
626 .into_iter()
627 .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
628 .sorted_by_key(cmp)
629 .collect::<Vec<_>>();
630 let expected = expected
631 .into_iter()
632 .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })
633 .sorted_by_key(cmp)
634 .collect::<Vec<_>>();
635
636 assert_eq!(expected, navs);
637 }
638
639 fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
640 let (analysis, position) = fixture::position(ra_fixture);
641 let navs = analysis
642 .goto_definition(position, &TEST_CONFIG)
643 .unwrap()
644 .expect("no definition found")
645 .info;
646
647 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
648 }
649
650 fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
651 let (analysis, position, _) = fixture::annotations(ra_fixture);
652 let navs = analysis
653 .goto_definition(position, &TEST_CONFIG)
654 .unwrap()
655 .expect("no definition found")
656 .info;
657 assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
658 let Some(target) = navs.into_iter().next() else {
659 panic!("expected single navigation target but encountered none");
660 };
661 assert_eq!(target.name, SmolStr::new_inline(expected_name));
662 }
663
664 #[test]
665 fn goto_def_pat_range_to_inclusive() {
666 check_name(
667 "RangeToInclusive",
668 r#"
669//- minicore: range
670fn f(ch: char) -> bool {
671 match ch {
672 ..$0='z' => true,
673 _ => false
674 }
675}
676"#,
677 );
678 }
679
680 #[test]
681 fn goto_def_pat_range_to() {
682 check_name(
683 "RangeTo",
684 r#"
685//- minicore: range
686fn f(ch: char) -> bool {
687 match ch {
688 .$0.'z' => true,
689 _ => false
690 }
691}
692"#,
693 );
694 }
695
696 #[test]
697 fn goto_def_pat_range() {
698 check_name(
699 "Range",
700 r#"
701//- minicore: range
702fn f(ch: char) -> bool {
703 match ch {
704 'a'.$0.'z' => true,
705 _ => false
706 }
707}
708"#,
709 );
710 }
711
712 #[test]
713 fn goto_def_pat_range_inclusive() {
714 check_name(
715 "RangeInclusive",
716 r#"
717//- minicore: range
718fn f(ch: char) -> bool {
719 match ch {
720 'a'..$0='z' => true,
721 _ => false
722 }
723}
724"#,
725 );
726 }
727
728 #[test]
729 fn goto_def_pat_range_from() {
730 check_name(
731 "RangeFrom",
732 r#"
733//- minicore: range
734fn f(ch: char) -> bool {
735 match ch {
736 'a'..$0 => true,
737 _ => false
738 }
739}
740"#,
741 );
742 }
743
744 #[test]
745 fn goto_def_expr_range() {
746 check_name(
747 "Range",
748 r#"
749//- minicore: range
750let x = 0.$0.1;
751"#,
752 );
753 }
754
755 #[test]
756 fn goto_def_expr_range_from() {
757 check_name(
758 "RangeFrom",
759 r#"
760//- minicore: range
761fn f(arr: &[i32]) -> &[i32] {
762 &arr[0.$0.]
763}
764"#,
765 );
766 }
767
768 #[test]
769 fn goto_def_expr_range_inclusive() {
770 check_name(
771 "RangeInclusive",
772 r#"
773//- minicore: range
774let x = 0.$0.=1;
775"#,
776 );
777 }
778
779 #[test]
780 fn goto_def_expr_range_full() {
781 check_name(
782 "RangeFull",
783 r#"
784//- minicore: range
785fn f(arr: &[i32]) -> &[i32] {
786 &arr[.$0.]
787}
788"#,
789 );
790 }
791
792 #[test]
793 fn goto_def_expr_range_to() {
794 check_name(
795 "RangeTo",
796 r#"
797//- minicore: range
798fn f(arr: &[i32]) -> &[i32] {
799 &arr[.$0.10]
800}
801"#,
802 );
803 }
804
805 #[test]
806 fn goto_def_expr_range_to_inclusive() {
807 check_name(
808 "RangeToInclusive",
809 r#"
810//- minicore: range
811fn f(arr: &[i32]) -> &[i32] {
812 &arr[.$0.=10]
813}
814"#,
815 );
816 }
817
818 #[test]
819 fn goto_def_in_included_file() {
820 check(
821 r#"
822//- minicore:include
823//- /main.rs
824
825include!("a.rs");
826
827fn main() {
828 foo();
829}
830
831//- /a.rs
832fn func_in_include() {
833 //^^^^^^^^^^^^^^^
834}
835
836fn foo() {
837 func_in_include$0();
838}
839"#,
840 );
841 }
842
843 #[test]
844 fn goto_def_in_included_file_nested() {
845 check(
846 r#"
847//- minicore:include
848//- /main.rs
849
850macro_rules! passthrough {
851 ($($tt:tt)*) => { $($tt)* }
852}
853
854passthrough!(include!("a.rs"));
855
856fn main() {
857 foo();
858}
859
860//- /a.rs
861fn func_in_include() {
862 //^^^^^^^^^^^^^^^
863}
864
865fn foo() {
866 func_in_include$0();
867}
868"#,
869 );
870 }
871
872 #[test]
873 fn goto_def_in_included_file_inside_mod() {
874 check(
875 r#"
876//- minicore:include
877//- /main.rs
878mod a {
879 include!("b.rs");
880}
881//- /b.rs
882fn func_in_include() {
883 //^^^^^^^^^^^^^^^
884}
885fn foo() {
886 func_in_include$0();
887}
888"#,
889 );
890
891 check(
892 r#"
893//- minicore:include
894//- /main.rs
895mod a {
896 include!("a.rs");
897}
898//- /a.rs
899fn func_in_include() {
900 //^^^^^^^^^^^^^^^
901}
902
903fn foo() {
904 func_in_include$0();
905}
906"#,
907 );
908 }
909
910 #[test]
911 fn goto_def_if_items_same_name() {
912 check(
913 r#"
914trait Trait {
915 type A;
916 const A: i32;
917 //^
918}
919
920struct T;
921impl Trait for T {
922 type A = i32;
923 const A$0: i32 = -9;
924}"#,
925 );
926 }
927 #[test]
928 fn goto_def_in_mac_call_in_attr_invoc() {
929 check(
930 r#"
931//- proc_macros: identity
932pub struct Struct {
933 // ^^^^^^
934 field: i32,
935}
936
937macro_rules! identity {
938 ($($tt:tt)*) => {$($tt)*};
939}
940
941#[proc_macros::identity]
942fn function() {
943 identity!(Struct$0 { field: 0 });
944}
945
946"#,
947 )
948 }
949
950 #[test]
951 fn goto_def_for_extern_crate() {
952 check(
953 r#"
954//- /main.rs crate:main deps:std
955extern crate std$0;
956//- /std/lib.rs crate:std
957// empty
958//^file
959"#,
960 )
961 }
962
963 #[test]
964 fn goto_def_for_renamed_extern_crate() {
965 check(
966 r#"
967//- /main.rs crate:main deps:std
968extern crate std as abc$0;
969//- /std/lib.rs crate:std
970// empty
971//^file
972"#,
973 )
974 }
975
976 #[test]
977 fn goto_def_in_items() {
978 check(
979 r#"
980struct Foo;
981 //^^^
982enum E { X(Foo$0) }
983"#,
984 );
985 }
986
987 #[test]
988 fn goto_def_at_start_of_item() {
989 check(
990 r#"
991struct Foo;
992 //^^^
993enum E { X($0Foo) }
994"#,
995 );
996 }
997
998 #[test]
999 fn goto_definition_resolves_correct_name() {
1000 check(
1001 r#"
1002//- /lib.rs
1003use a::Foo;
1004mod a;
1005mod b;
1006enum E { X(Foo$0) }
1007
1008//- /a.rs
1009pub struct Foo;
1010 //^^^
1011//- /b.rs
1012pub struct Foo;
1013"#,
1014 );
1015 }
1016
1017 #[test]
1018 fn goto_def_for_module_declaration() {
1019 check(
1020 r#"
1021//- /lib.rs
1022mod $0foo;
1023
1024//- /foo.rs
1025// empty
1026//^file
1027"#,
1028 );
1029
1030 check(
1031 r#"
1032//- /lib.rs
1033mod $0foo;
1034
1035//- /foo/mod.rs
1036// empty
1037//^file
1038"#,
1039 );
1040 }
1041
1042 #[test]
1043 fn goto_def_for_macros() {
1044 check(
1045 r#"
1046macro_rules! foo { () => { () } }
1047 //^^^
1048fn bar() {
1049 $0foo!();
1050}
1051"#,
1052 );
1053 }
1054
1055 #[test]
1056 fn goto_def_for_macros_from_other_crates() {
1057 check(
1058 r#"
1059//- /lib.rs crate:main deps:foo
1060use foo::foo;
1061fn bar() {
1062 $0foo!();
1063}
1064
1065//- /foo/lib.rs crate:foo
1066#[macro_export]
1067macro_rules! foo { () => { () } }
1068 //^^^
1069"#,
1070 );
1071 }
1072
1073 #[test]
1074 fn goto_def_for_macros_in_use_tree() {
1075 check(
1076 r#"
1077//- /lib.rs crate:main deps:foo
1078use foo::foo$0;
1079
1080//- /foo/lib.rs crate:foo
1081#[macro_export]
1082macro_rules! foo { () => { () } }
1083 //^^^
1084"#,
1085 );
1086 }
1087
1088 #[test]
1089 fn goto_def_for_macro_defined_fn_with_arg() {
1090 check(
1091 r#"
1092//- /lib.rs
1093macro_rules! define_fn {
1094 ($name:ident) => (fn $name() {})
1095}
1096
1097define_fn!(foo);
1098 //^^^
1099
1100fn bar() {
1101 $0foo();
1102}
1103"#,
1104 );
1105 }
1106
1107 #[test]
1108 fn goto_def_for_macro_defined_fn_no_arg() {
1109 check(
1110 r#"
1111//- /lib.rs
1112macro_rules! define_fn {
1113 () => (fn foo() {})
1114 //^^^
1115}
1116
1117 define_fn!();
1118//^^^^^^^^^^
1119fn bar() {
1120 $0foo();
1121}
1122"#,
1123 );
1124 }
1125
1126 #[test]
1127 fn goto_definition_works_for_macro_inside_pattern() {
1128 check(
1129 r#"
1130//- /lib.rs
1131macro_rules! foo {() => {0}}
1132 //^^^
1133
1134fn bar() {
1135 match (0,1) {
1136 ($0foo!(), _) => {}
1137 }
1138}
1139"#,
1140 );
1141 }
1142
1143 #[test]
1144 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
1145 check(
1146 r#"
1147//- /lib.rs
1148macro_rules! foo {() => {0}}
1149 //^^^
1150fn bar() {
1151 match 0 {
1152 $0foo!() => {}
1153 }
1154}
1155"#,
1156 );
1157 }
1158
1159 #[test]
1160 fn goto_definition_works_for_consts_inside_range_pattern() {
1161 check(
1162 r#"
1163//- /lib.rs
1164const A: u32 = 0;
1165 //^
1166
1167fn bar(v: u32) {
1168 match v {
1169 0..=$0A => {}
1170 _ => {}
1171 }
1172}
1173"#,
1174 );
1175 }
1176
1177 #[test]
1178 fn goto_def_for_use_alias() {
1179 check(
1180 r#"
1181//- /lib.rs crate:main deps:foo
1182use foo as bar$0;
1183
1184//- /foo/lib.rs crate:foo
1185// empty
1186//^file
1187"#,
1188 );
1189 }
1190
1191 #[test]
1192 fn goto_def_for_use_alias_foo_macro() {
1193 check(
1194 r#"
1195//- /lib.rs crate:main deps:foo
1196use foo::foo as bar$0;
1197
1198//- /foo/lib.rs crate:foo
1199#[macro_export]
1200macro_rules! foo { () => { () } }
1201 //^^^
1202"#,
1203 );
1204 }
1205
1206 #[test]
1207 fn goto_def_for_methods() {
1208 check(
1209 r#"
1210struct Foo;
1211impl Foo {
1212 fn frobnicate(&self) { }
1213 //^^^^^^^^^^
1214}
1215
1216fn bar(foo: &Foo) {
1217 foo.frobnicate$0();
1218}
1219"#,
1220 );
1221 }
1222
1223 #[test]
1224 fn goto_def_for_fields() {
1225 check(
1226 r#"
1227struct Foo {
1228 spam: u32,
1229} //^^^^
1230
1231fn bar(foo: &Foo) {
1232 foo.spam$0;
1233}
1234"#,
1235 );
1236 }
1237
1238 #[test]
1239 fn goto_def_for_record_fields() {
1240 check(
1241 r#"
1242//- /lib.rs
1243struct Foo {
1244 spam: u32,
1245} //^^^^
1246
1247fn bar() -> Foo {
1248 Foo {
1249 spam$0: 0,
1250 }
1251}
1252"#,
1253 );
1254 }
1255
1256 #[test]
1257 fn goto_def_for_record_pat_fields() {
1258 check(
1259 r#"
1260//- /lib.rs
1261struct Foo {
1262 spam: u32,
1263} //^^^^
1264
1265fn bar(foo: Foo) -> Foo {
1266 let Foo { spam$0: _, } = foo
1267}
1268"#,
1269 );
1270 }
1271
1272 #[test]
1273 fn goto_def_for_record_fields_macros() {
1274 check(
1275 r"
1276macro_rules! m { () => { 92 };}
1277struct Foo { spam: u32 }
1278 //^^^^
1279
1280fn bar() -> Foo {
1281 Foo { spam$0: m!() }
1282}
1283",
1284 );
1285 }
1286
1287 #[test]
1288 fn goto_for_tuple_fields() {
1289 check(
1290 r#"
1291struct Foo(u32);
1292 //^^^
1293
1294fn bar() {
1295 let foo = Foo(0);
1296 foo.$00;
1297}
1298"#,
1299 );
1300 }
1301
1302 #[test]
1303 fn goto_def_for_ufcs_inherent_methods() {
1304 check(
1305 r#"
1306struct Foo;
1307impl Foo {
1308 fn frobnicate() { }
1309} //^^^^^^^^^^
1310
1311fn bar(foo: &Foo) {
1312 Foo::frobnicate$0();
1313}
1314"#,
1315 );
1316 }
1317
1318 #[test]
1319 fn goto_def_for_ufcs_trait_methods_through_traits() {
1320 check(
1321 r#"
1322trait Foo {
1323 fn frobnicate();
1324} //^^^^^^^^^^
1325
1326fn bar() {
1327 Foo::frobnicate$0();
1328}
1329"#,
1330 );
1331 }
1332
1333 #[test]
1334 fn goto_def_for_ufcs_trait_methods_through_self() {
1335 check(
1336 r#"
1337struct Foo;
1338trait Trait {
1339 fn frobnicate();
1340} //^^^^^^^^^^
1341impl Trait for Foo {}
1342
1343fn bar() {
1344 Foo::frobnicate$0();
1345}
1346"#,
1347 );
1348 }
1349
1350 #[test]
1351 fn goto_definition_on_self() {
1352 check(
1353 r#"
1354struct Foo;
1355impl Foo {
1356 //^^^
1357 pub fn new() -> Self {
1358 Self$0 {}
1359 }
1360}
1361"#,
1362 );
1363 check(
1364 r#"
1365struct Foo;
1366impl Foo {
1367 //^^^
1368 pub fn new() -> Self$0 {
1369 Self {}
1370 }
1371}
1372"#,
1373 );
1374
1375 check(
1376 r#"
1377enum Foo { A }
1378impl Foo {
1379 //^^^
1380 pub fn new() -> Self$0 {
1381 Foo::A
1382 }
1383}
1384"#,
1385 );
1386
1387 check(
1388 r#"
1389enum Foo { A }
1390impl Foo {
1391 //^^^
1392 pub fn thing(a: &Self$0) {
1393 }
1394}
1395"#,
1396 );
1397 }
1398
1399 #[test]
1400 fn goto_definition_on_self_in_trait_impl() {
1401 check(
1402 r#"
1403struct Foo;
1404trait Make {
1405 fn new() -> Self;
1406}
1407impl Make for Foo {
1408 //^^^
1409 fn new() -> Self {
1410 Self$0 {}
1411 }
1412}
1413"#,
1414 );
1415
1416 check(
1417 r#"
1418struct Foo;
1419trait Make {
1420 fn new() -> Self;
1421}
1422impl Make for Foo {
1423 //^^^
1424 fn new() -> Self$0 {
1425 Self {}
1426 }
1427}
1428"#,
1429 );
1430 }
1431
1432 #[test]
1433 fn goto_def_when_used_on_definition_name_itself() {
1434 check(
1435 r#"
1436struct Foo$0 { value: u32 }
1437 //^^^
1438 "#,
1439 );
1440
1441 check(
1442 r#"
1443struct Foo {
1444 field$0: string,
1445} //^^^^^
1446"#,
1447 );
1448
1449 check(
1450 r#"
1451fn foo_test$0() { }
1452 //^^^^^^^^
1453"#,
1454 );
1455
1456 check(
1457 r#"
1458enum Foo$0 { Variant }
1459 //^^^
1460"#,
1461 );
1462
1463 check(
1464 r#"
1465enum Foo {
1466 Variant1,
1467 Variant2$0,
1468 //^^^^^^^^
1469 Variant3,
1470}
1471"#,
1472 );
1473
1474 check(
1475 r#"
1476static INNER$0: &str = "";
1477 //^^^^^
1478"#,
1479 );
1480
1481 check(
1482 r#"
1483const INNER$0: &str = "";
1484 //^^^^^
1485"#,
1486 );
1487
1488 check(
1489 r#"
1490type Thing$0 = Option<()>;
1491 //^^^^^
1492"#,
1493 );
1494
1495 check(
1496 r#"
1497trait Foo$0 { }
1498 //^^^
1499"#,
1500 );
1501
1502 check(
1503 r#"
1504trait Foo$0 = ;
1505 //^^^
1506"#,
1507 );
1508
1509 check(
1510 r#"
1511mod bar$0 { }
1512 //^^^
1513"#,
1514 );
1515 }
1516
1517 #[test]
1518 fn goto_from_macro() {
1519 check(
1520 r#"
1521macro_rules! id {
1522 ($($tt:tt)*) => { $($tt)* }
1523}
1524fn foo() {}
1525 //^^^
1526id! {
1527 fn bar() {
1528 fo$0o();
1529 }
1530}
1531mod confuse_index { fn foo(); }
1532"#,
1533 );
1534 }
1535
1536 #[test]
1537 fn goto_through_format() {
1538 check(
1539 r#"
1540//- minicore: fmt
1541#[macro_export]
1542macro_rules! format {
1543 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
1544}
1545pub mod __export {
1546 pub use core::format_args;
1547 fn foo() {} // for index confusion
1548}
1549fn foo() -> i8 {}
1550 //^^^
1551fn test() {
1552 format!("{}", fo$0o())
1553}
1554"#,
1555 );
1556 }
1557
1558 #[test]
1559 fn goto_through_included_file() {
1560 check(
1561 r#"
1562//- /main.rs
1563#[rustc_builtin_macro]
1564macro_rules! include {}
1565
1566include!("foo.rs");
1567
1568fn f() {
1569 foo$0();
1570}
1571
1572mod confuse_index {
1573 pub fn foo() {}
1574}
1575
1576//- /foo.rs
1577fn foo() {}
1578 //^^^
1579 "#,
1580 );
1581 }
1582
1583 #[test]
1584 fn goto_through_included_file_struct_with_doc_comment() {
1585 check(
1586 r#"
1587//- /main.rs
1588#[rustc_builtin_macro]
1589macro_rules! include {}
1590
1591include!("foo.rs");
1592
1593fn f() {
1594 let x = Foo$0;
1595}
1596
1597mod confuse_index {
1598 pub struct Foo;
1599}
1600
1601//- /foo.rs
1602/// This is a doc comment
1603pub struct Foo;
1604 //^^^
1605 "#,
1606 );
1607 }
1608
1609 #[test]
1610 fn goto_for_type_param() {
1611 check(
1612 r#"
1613struct Foo<T: Clone> { t: $0T }
1614 //^
1615"#,
1616 );
1617 }
1618
1619 #[test]
1620 fn goto_within_macro() {
1621 check(
1622 r#"
1623macro_rules! id {
1624 ($($tt:tt)*) => ($($tt)*)
1625}
1626
1627fn foo() {
1628 let x = 1;
1629 //^
1630 id!({
1631 let y = $0x;
1632 let z = y;
1633 });
1634}
1635"#,
1636 );
1637
1638 check(
1639 r#"
1640macro_rules! id {
1641 ($($tt:tt)*) => ($($tt)*)
1642}
1643
1644fn foo() {
1645 let x = 1;
1646 id!({
1647 let y = x;
1648 //^
1649 let z = $0y;
1650 });
1651}
1652"#,
1653 );
1654 }
1655
1656 #[test]
1657 fn goto_def_in_local_fn() {
1658 check(
1659 r#"
1660fn main() {
1661 fn foo() {
1662 let x = 92;
1663 //^
1664 $0x;
1665 }
1666}
1667"#,
1668 );
1669 }
1670
1671 #[test]
1672 fn goto_def_in_local_macro() {
1673 check(
1674 r#"
1675fn bar() {
1676 macro_rules! foo { () => { () } }
1677 //^^^
1678 $0foo!();
1679}
1680"#,
1681 );
1682 }
1683
1684 #[test]
1685 fn goto_def_for_field_init_shorthand() {
1686 check(
1687 r#"
1688struct Foo { x: i32 }
1689 //^
1690fn main() {
1691 let x = 92;
1692 //^
1693 Foo { x$0 };
1694}
1695"#,
1696 )
1697 }
1698
1699 #[test]
1700 fn goto_def_for_enum_variant_field() {
1701 check(
1702 r#"
1703enum Foo {
1704 Bar { x: i32 }
1705 //^
1706}
1707fn baz(foo: Foo) {
1708 match foo {
1709 Foo::Bar { x$0 } => x
1710 //^
1711 };
1712}
1713"#,
1714 );
1715 }
1716
1717 #[test]
1718 fn goto_def_for_enum_variant_self_pattern_const() {
1719 check(
1720 r#"
1721enum Foo { Bar }
1722 //^^^
1723impl Foo {
1724 fn baz(self) {
1725 match self { Self::Bar$0 => {} }
1726 }
1727}
1728"#,
1729 );
1730 }
1731
1732 #[test]
1733 fn goto_def_for_enum_variant_self_pattern_record() {
1734 check(
1735 r#"
1736enum Foo { Bar { val: i32 } }
1737 //^^^
1738impl Foo {
1739 fn baz(self) -> i32 {
1740 match self { Self::Bar$0 { val } => {} }
1741 }
1742}
1743"#,
1744 );
1745 }
1746
1747 #[test]
1748 fn goto_def_for_enum_variant_self_expr_const() {
1749 check(
1750 r#"
1751enum Foo { Bar }
1752 //^^^
1753impl Foo {
1754 fn baz(self) { Self::Bar$0; }
1755}
1756"#,
1757 );
1758 }
1759
1760 #[test]
1761 fn goto_def_for_enum_variant_self_expr_record() {
1762 check(
1763 r#"
1764enum Foo { Bar { val: i32 } }
1765 //^^^
1766impl Foo {
1767 fn baz(self) { Self::Bar$0 {val: 4}; }
1768}
1769"#,
1770 );
1771 }
1772
1773 #[test]
1774 fn goto_def_for_type_alias_generic_parameter() {
1775 check(
1776 r#"
1777type Alias<T> = T$0;
1778 //^
1779"#,
1780 )
1781 }
1782
1783 #[test]
1784 fn goto_def_for_macro_container() {
1785 check(
1786 r#"
1787//- /lib.rs crate:main deps:foo
1788foo::module$0::mac!();
1789
1790//- /foo/lib.rs crate:foo
1791pub mod module {
1792 //^^^^^^
1793 #[macro_export]
1794 macro_rules! _mac { () => { () } }
1795 pub use crate::_mac as mac;
1796}
1797"#,
1798 );
1799 }
1800
1801 #[test]
1802 fn goto_def_for_assoc_ty_in_path() {
1803 check(
1804 r#"
1805trait Iterator {
1806 type Item;
1807 //^^^^
1808}
1809
1810fn f() -> impl Iterator<Item$0 = u8> {}
1811"#,
1812 );
1813 }
1814
1815 #[test]
1816 fn goto_def_for_super_assoc_ty_in_path() {
1817 check(
1818 r#"
1819trait Super {
1820 type Item;
1821 //^^^^
1822}
1823
1824trait Sub: Super {}
1825
1826fn f() -> impl Sub<Item$0 = u8> {}
1827"#,
1828 );
1829 }
1830
1831 #[test]
1832 fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {
1833 check(
1834 r#"
1835mod bar {
1836 pub struct Foo {}
1837 //^^^
1838 pub fn Foo() {}
1839}
1840
1841fn baz() {
1842 let _foo_enum: bar::Foo$0 = bar::Foo {};
1843}
1844 "#,
1845 )
1846 }
1847
1848 #[test]
1849 fn unknown_assoc_ty() {
1850 check_unresolved(
1851 r#"
1852trait Iterator { type Item; }
1853fn f() -> impl Iterator<Invalid$0 = u8> {}
1854"#,
1855 )
1856 }
1857
1858 #[test]
1859 fn goto_def_for_assoc_ty_in_path_multiple() {
1860 check(
1861 r#"
1862trait Iterator {
1863 type A;
1864 //^
1865 type B;
1866}
1867
1868fn f() -> impl Iterator<A$0 = u8, B = ()> {}
1869"#,
1870 );
1871 check(
1872 r#"
1873trait Iterator {
1874 type A;
1875 type B;
1876 //^
1877}
1878
1879fn f() -> impl Iterator<A = u8, B$0 = ()> {}
1880"#,
1881 );
1882 }
1883
1884 #[test]
1885 fn goto_def_for_assoc_ty_ufcs() {
1886 check(
1887 r#"
1888trait Iterator {
1889 type Item;
1890 //^^^^
1891}
1892
1893fn g() -> <() as Iterator<Item$0 = ()>>::Item {}
1894"#,
1895 );
1896 }
1897
1898 #[test]
1899 fn goto_def_for_assoc_ty_ufcs_multiple() {
1900 check(
1901 r#"
1902trait Iterator {
1903 type A;
1904 //^
1905 type B;
1906}
1907
1908fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}
1909"#,
1910 );
1911 check(
1912 r#"
1913trait Iterator {
1914 type A;
1915 type B;
1916 //^
1917}
1918
1919fn g() -> <() as Iterator<A = (), B$0 = u8>>::A {}
1920"#,
1921 );
1922 }
1923
1924 #[test]
1925 fn goto_self_param_ty_specified() {
1926 check(
1927 r#"
1928struct Foo {}
1929
1930impl Foo {
1931 fn bar(self: &Foo) {
1932 //^^^^
1933 let foo = sel$0f;
1934 }
1935}"#,
1936 )
1937 }
1938
1939 #[test]
1940 fn goto_self_param_on_decl() {
1941 check(
1942 r#"
1943struct Foo {}
1944
1945impl Foo {
1946 fn bar(&self$0) {
1947 //^^^^
1948 }
1949}"#,
1950 )
1951 }
1952
1953 #[test]
1954 fn goto_lifetime_param_on_decl() {
1955 check(
1956 r#"
1957fn foo<'foobar$0>(_: &'foobar ()) {
1958 //^^^^^^^
1959}"#,
1960 )
1961 }
1962
1963 #[test]
1964 fn goto_lifetime_param_decl() {
1965 check(
1966 r#"
1967fn foo<'foobar>(_: &'foobar$0 ()) {
1968 //^^^^^^^
1969}"#,
1970 )
1971 }
1972
1973 #[test]
1974 fn goto_lifetime_param_decl_nested() {
1975 check(
1976 r#"
1977fn foo<'foobar>(_: &'foobar ()) {
1978 fn foo<'foobar>(_: &'foobar$0 ()) {}
1979 //^^^^^^^
1980}"#,
1981 )
1982 }
1983
1984 #[test]
1985 fn goto_lifetime_hrtb() {
1986 check_unresolved(
1988 r#"
1989trait Foo<T> {}
1990fn foo<T>() where for<'a> T: Foo<&'a$0 (u8, u16)>, {}
1991 //^^
1992"#,
1993 );
1994 check_unresolved(
1995 r#"
1996trait Foo<T> {}
1997fn foo<T>() where for<'a$0> T: Foo<&'a (u8, u16)>, {}
1998 //^^
1999"#,
2000 );
2001 }
2002
2003 #[test]
2004 fn goto_lifetime_hrtb_for_type() {
2005 check_unresolved(
2007 r#"trait Foo<T> {}
2008fn foo<T>() where T: for<'a> Foo<&'a$0 (u8, u16)>, {}
2009 //^^
2010"#,
2011 );
2012 }
2013
2014 #[test]
2015 fn goto_label() {
2016 check(
2017 r#"
2018fn foo<'foo>(_: &'foo ()) {
2019 'foo: {
2020 //^^^^
2021 'bar: loop {
2022 break 'foo$0;
2023 }
2024 }
2025}"#,
2026 )
2027 }
2028
2029 #[test]
2030 fn goto_def_for_intra_doc_link_same_file() {
2031 check(
2032 r#"
2033/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
2034pub fn bar() { }
2035
2036/// You might want to see [`std::fs::read()`] too.
2037pub fn foo() { }
2038 //^^^
2039
2040}"#,
2041 )
2042 }
2043
2044 #[test]
2045 fn goto_def_for_intra_doc_link_outer_same_file() {
2046 check(
2047 r#"
2048/// [`S$0`]
2049mod m {
2050 //! [`super::S`]
2051}
2052struct S;
2053 //^
2054 "#,
2055 );
2056
2057 check(
2058 r#"
2059/// [`S$0`]
2060mod m {}
2061struct S;
2062 //^
2063 "#,
2064 );
2065
2066 check(
2067 r#"
2068/// [`S$0`]
2069fn f() {
2070 //! [`S`]
2071}
2072struct S;
2073 //^
2074 "#,
2075 );
2076 }
2077
2078 #[test]
2079 fn goto_def_for_intra_doc_link_inner_same_file() {
2080 check(
2081 r#"
2082/// [`S`]
2083mod m {
2084 //! [`super::S$0`]
2085}
2086struct S;
2087 //^
2088 "#,
2089 );
2090
2091 check(
2092 r#"
2093mod m {
2094 //! [`super::S$0`]
2095}
2096struct S;
2097 //^
2098 "#,
2099 );
2100
2101 check(
2102 r#"
2103fn f() {
2104 //! [`S$0`]
2105}
2106struct S;
2107 //^
2108 "#,
2109 );
2110 }
2111
2112 #[test]
2113 fn goto_def_for_intra_doc_link_inner() {
2114 check(
2115 r#"
2116//- /main.rs
2117mod m;
2118struct S;
2119 //^
2120
2121//- /m.rs
2122//! [`super::S$0`]
2123"#,
2124 )
2125 }
2126
2127 #[test]
2128 fn goto_incomplete_field() {
2129 check(
2130 r#"
2131struct A { a: u32 }
2132 //^
2133fn foo() { A { a$0: }; }
2134"#,
2135 )
2136 }
2137
2138 #[test]
2139 fn goto_proc_macro() {
2140 check(
2141 r#"
2142//- /main.rs crate:main deps:mac
2143use mac::fn_macro;
2144
2145fn_macro$0!();
2146
2147//- /mac.rs crate:mac
2148#![crate_type="proc-macro"]
2149#[proc_macro]
2150fn fn_macro() {}
2151 //^^^^^^^^
2152 "#,
2153 )
2154 }
2155
2156 #[test]
2157 fn goto_intra_doc_links() {
2158 check(
2159 r#"
2160
2161pub mod theitem {
2162 /// This is the item. Cool!
2163 pub struct TheItem;
2164 //^^^^^^^
2165}
2166
2167/// Gives you a [`TheItem$0`].
2168///
2169/// [`TheItem`]: theitem::TheItem
2170pub fn gimme() -> theitem::TheItem {
2171 theitem::TheItem
2172}
2173"#,
2174 );
2175 }
2176
2177 #[test]
2178 fn goto_ident_from_pat_macro() {
2179 check(
2180 r#"
2181macro_rules! pat {
2182 ($name:ident) => { Enum::Variant1($name) }
2183}
2184
2185enum Enum {
2186 Variant1(u8),
2187 Variant2,
2188}
2189
2190fn f(e: Enum) {
2191 match e {
2192 pat!(bind) => {
2193 //^^^^
2194 bind$0
2195 }
2196 Enum::Variant2 => {}
2197 }
2198}
2199"#,
2200 );
2201 }
2202
2203 #[test]
2204 fn goto_include() {
2205 check(
2206 r#"
2207//- /main.rs
2208
2209#[rustc_builtin_macro]
2210macro_rules! include_str {}
2211
2212fn main() {
2213 let str = include_str!("foo.txt$0");
2214}
2215//- /foo.txt
2216// empty
2217//^file
2218"#,
2219 );
2220 }
2221
2222 #[test]
2223 fn goto_include_has_eager_input() {
2224 check(
2225 r#"
2226//- /main.rs
2227#[rustc_builtin_macro]
2228macro_rules! include_str {}
2229#[rustc_builtin_macro]
2230macro_rules! concat {}
2231
2232fn main() {
2233 let str = include_str!(concat!("foo", ".tx$0t"));
2234}
2235//- /foo.txt
2236// empty
2237//^file
2238"#,
2239 );
2240 }
2241
2242 #[test]
2244 #[should_panic]
2246 fn goto_doc_include_str() {
2247 check(
2248 r#"
2249//- /main.rs
2250#[rustc_builtin_macro]
2251macro_rules! include_str {}
2252
2253#[doc = include_str!("docs.md$0")]
2254struct Item;
2255
2256//- /docs.md
2257// docs
2258//^file
2259"#,
2260 );
2261 }
2262
2263 #[test]
2264 fn goto_shadow_include() {
2265 check(
2266 r#"
2267//- /main.rs
2268macro_rules! include {
2269 ("included.rs") => {}
2270}
2271
2272include!("included.rs$0");
2273
2274//- /included.rs
2275// empty
2276"#,
2277 );
2278 }
2279
2280 mod goto_impl_of_trait_fn {
2281 use super::check;
2282 #[test]
2283 fn cursor_on_impl() {
2284 check(
2285 r#"
2286trait Twait {
2287 fn a();
2288}
2289
2290struct Stwuct;
2291
2292impl Twait for Stwuct {
2293 fn a$0();
2294 //^
2295}
2296 "#,
2297 );
2298 }
2299 #[test]
2300 fn method_call() {
2301 check(
2302 r#"
2303trait Twait {
2304 fn a(&self);
2305}
2306
2307struct Stwuct;
2308
2309impl Twait for Stwuct {
2310 fn a(&self){};
2311 //^
2312}
2313fn f() {
2314 let s = Stwuct;
2315 s.a$0();
2316}
2317 "#,
2318 );
2319 }
2320 #[test]
2321 fn method_call_inside_block() {
2322 check(
2323 r#"
2324trait Twait {
2325 fn a(&self);
2326}
2327
2328fn outer() {
2329 struct Stwuct;
2330
2331 impl Twait for Stwuct {
2332 fn a(&self){}
2333 //^
2334 }
2335 fn f() {
2336 let s = Stwuct;
2337 s.a$0();
2338 }
2339}
2340 "#,
2341 );
2342 }
2343 #[test]
2344 fn path_call() {
2345 check(
2346 r#"
2347trait Twait {
2348 fn a(&self);
2349}
2350
2351struct Stwuct;
2352
2353impl Twait for Stwuct {
2354 fn a(&self){};
2355 //^
2356}
2357fn f() {
2358 let s = Stwuct;
2359 Stwuct::a$0(&s);
2360}
2361 "#,
2362 );
2363 }
2364 #[test]
2365 fn where_clause_can_work() {
2366 check(
2367 r#"
2368trait G {
2369 fn g(&self);
2370}
2371trait Bound{}
2372trait EA{}
2373struct Gen<T>(T);
2374impl <T:EA> G for Gen<T> {
2375 fn g(&self) {
2376 }
2377}
2378impl <T> G for Gen<T>
2379where T : Bound
2380{
2381 fn g(&self){
2382 //^
2383 }
2384}
2385struct A;
2386impl Bound for A{}
2387fn f() {
2388 let g = Gen::<A>(A);
2389 g.g$0();
2390}
2391 "#,
2392 );
2393 }
2394 #[test]
2395 fn wc_case_is_ok() {
2396 check(
2397 r#"
2398trait G {
2399 fn g(&self);
2400}
2401trait BParent{}
2402trait Bound: BParent{}
2403struct Gen<T>(T);
2404impl <T> G for Gen<T>
2405where T : Bound
2406{
2407 fn g(&self){
2408 //^
2409 }
2410}
2411struct A;
2412impl Bound for A{}
2413fn f() {
2414 let g = Gen::<A>(A);
2415 g.g$0();
2416}
2417"#,
2418 );
2419 }
2420
2421 #[test]
2422 fn method_call_defaulted() {
2423 check(
2424 r#"
2425trait Twait {
2426 fn a(&self) {}
2427 //^
2428}
2429
2430struct Stwuct;
2431
2432impl Twait for Stwuct {
2433}
2434fn f() {
2435 let s = Stwuct;
2436 s.a$0();
2437}
2438 "#,
2439 );
2440 }
2441
2442 #[test]
2443 fn method_call_on_generic() {
2444 check(
2445 r#"
2446trait Twait {
2447 fn a(&self) {}
2448 //^
2449}
2450
2451fn f<T: Twait>(s: T) {
2452 s.a$0();
2453}
2454 "#,
2455 );
2456 }
2457 }
2458
2459 #[test]
2460 fn goto_def_of_trait_impl_const() {
2461 check(
2462 r#"
2463trait Twait {
2464 const NOMS: bool;
2465 // ^^^^
2466}
2467
2468struct Stwuct;
2469
2470impl Twait for Stwuct {
2471 const NOMS$0: bool = true;
2472}
2473"#,
2474 );
2475 }
2476
2477 #[test]
2478 fn goto_def_of_trait_impl_type_alias() {
2479 check(
2480 r#"
2481trait Twait {
2482 type IsBad;
2483 // ^^^^^
2484}
2485
2486struct Stwuct;
2487
2488impl Twait for Stwuct {
2489 type IsBad$0 = !;
2490}
2491"#,
2492 );
2493 }
2494
2495 #[test]
2496 fn goto_def_derive_input() {
2497 check(
2498 r#"
2499 //- minicore:derive
2500 #[rustc_builtin_macro]
2501 pub macro Copy {}
2502 // ^^^^
2503 #[derive(Copy$0)]
2504 struct Foo;
2505 "#,
2506 );
2507 check(
2508 r#"
2509//- minicore:derive
2510#[rustc_builtin_macro]
2511pub macro Copy {}
2512 // ^^^^
2513#[cfg_attr(feature = "false", derive)]
2514#[derive(Copy$0)]
2515struct Foo;
2516 "#,
2517 );
2518 check(
2519 r#"
2520//- minicore:derive
2521mod foo {
2522 #[rustc_builtin_macro]
2523 pub macro Copy {}
2524 // ^^^^
2525}
2526#[derive(foo::Copy$0)]
2527struct Foo;
2528 "#,
2529 );
2530 check(
2531 r#"
2532//- minicore:derive
2533mod foo {
2534 // ^^^
2535 #[rustc_builtin_macro]
2536 pub macro Copy {}
2537}
2538#[derive(foo$0::Copy)]
2539struct Foo;
2540 "#,
2541 );
2542 }
2543
2544 #[test]
2545 fn goto_def_in_macro_multi() {
2546 check(
2547 r#"
2548struct Foo {
2549 foo: ()
2550 //^^^
2551}
2552macro_rules! foo {
2553 ($ident:ident) => {
2554 fn $ident(Foo { $ident }: Foo) {}
2555 }
2556}
2557 foo!(foo$0);
2558 //^^^
2559 //^^^
2560"#,
2561 );
2562 check(
2563 r#"
2564fn bar() {}
2565 //^^^
2566struct bar;
2567 //^^^
2568macro_rules! foo {
2569 ($ident:ident) => {
2570 fn foo() {
2571 let _: $ident = $ident;
2572 }
2573 }
2574}
2575
2576foo!(bar$0);
2577"#,
2578 );
2579 }
2580
2581 #[test]
2582 fn goto_await_poll() {
2583 check(
2584 r#"
2585//- minicore: future
2586
2587struct MyFut;
2588
2589impl core::future::Future for MyFut {
2590 type Output = ();
2591
2592 fn poll(
2593 //^^^^
2594 self: std::pin::Pin<&mut Self>,
2595 cx: &mut std::task::Context<'_>
2596 ) -> std::task::Poll<Self::Output>
2597 {
2598 ()
2599 }
2600}
2601
2602fn f() {
2603 MyFut.await$0;
2604}
2605"#,
2606 );
2607 }
2608
2609 #[test]
2610 fn goto_await_into_future_poll() {
2611 check(
2612 r#"
2613//- minicore: future
2614
2615struct Futurable;
2616
2617impl core::future::IntoFuture for Futurable {
2618 type IntoFuture = MyFut;
2619}
2620
2621struct MyFut;
2622
2623impl core::future::Future for MyFut {
2624 type Output = ();
2625
2626 fn poll(
2627 //^^^^
2628 self: std::pin::Pin<&mut Self>,
2629 cx: &mut std::task::Context<'_>
2630 ) -> std::task::Poll<Self::Output>
2631 {
2632 ()
2633 }
2634}
2635
2636fn f() {
2637 Futurable.await$0;
2638}
2639"#,
2640 );
2641 }
2642
2643 #[test]
2644 fn goto_try_op() {
2645 check(
2646 r#"
2647//- minicore: try
2648
2649struct Struct;
2650
2651impl core::ops::Try for Struct {
2652 fn branch(
2653 //^^^^^^
2654 self
2655 ) {}
2656}
2657
2658fn f() {
2659 Struct?$0;
2660}
2661"#,
2662 );
2663 }
2664
2665 #[test]
2666 fn goto_index_op() {
2667 check(
2668 r#"
2669//- minicore: index
2670
2671struct Struct;
2672
2673impl core::ops::Index<usize> for Struct {
2674 fn index(
2675 //^^^^^
2676 self
2677 ) {}
2678}
2679
2680fn f() {
2681 Struct[0]$0;
2682}
2683"#,
2684 );
2685 }
2686
2687 #[test]
2688 fn goto_index_mut_op() {
2689 check(
2690 r#"
2691//- minicore: index
2692
2693struct Foo;
2694struct Bar;
2695
2696impl core::ops::Index<usize> for Foo {
2697 type Output = Bar;
2698
2699 fn index(&self, index: usize) -> &Self::Output {}
2700}
2701
2702impl core::ops::IndexMut<usize> for Foo {
2703 fn index_mut(&mut self, index: usize) -> &mut Self::Output {}
2704 //^^^^^^^^^
2705}
2706
2707fn f() {
2708 let mut foo = Foo;
2709 foo[0]$0 = Bar;
2710}
2711"#,
2712 );
2713 }
2714
2715 #[test]
2716 fn goto_prefix_op() {
2717 check(
2718 r#"
2719//- minicore: deref
2720
2721struct Struct;
2722
2723impl core::ops::Deref for Struct {
2724 fn deref(
2725 //^^^^^
2726 self
2727 ) {}
2728}
2729
2730fn f() {
2731 $0*Struct;
2732}
2733"#,
2734 );
2735 }
2736
2737 #[test]
2738 fn goto_deref_mut() {
2739 check(
2740 r#"
2741//- minicore: deref, deref_mut
2742
2743struct Foo;
2744struct Bar;
2745
2746impl core::ops::Deref for Foo {
2747 type Target = Bar;
2748 fn deref(&self) -> &Self::Target {}
2749}
2750
2751impl core::ops::DerefMut for Foo {
2752 fn deref_mut(&mut self) -> &mut Self::Target {}
2753 //^^^^^^^^^
2754}
2755
2756fn f() {
2757 let a = Foo;
2758 $0*a = Bar;
2759}
2760"#,
2761 );
2762 }
2763
2764 #[test]
2765 fn goto_bin_op() {
2766 check(
2767 r#"
2768//- minicore: add
2769
2770struct Struct;
2771
2772impl core::ops::Add for Struct {
2773 fn add(
2774 //^^^
2775 self
2776 ) {}
2777}
2778
2779fn f() {
2780 Struct +$0 Struct;
2781}
2782"#,
2783 );
2784 }
2785
2786 #[test]
2787 fn goto_bin_op_multiple_impl() {
2788 check(
2789 r#"
2790//- minicore: add
2791struct S;
2792impl core::ops::Add for S {
2793 fn add(
2794 //^^^
2795 ) {}
2796}
2797impl core::ops::Add<usize> for S {
2798 fn add(
2799 ) {}
2800}
2801
2802fn f() {
2803 S +$0 S
2804}
2805"#,
2806 );
2807
2808 check(
2809 r#"
2810//- minicore: add
2811struct S;
2812impl core::ops::Add for S {
2813 fn add(
2814 ) {}
2815}
2816impl core::ops::Add<usize> for S {
2817 fn add(
2818 //^^^
2819 ) {}
2820}
2821
2822fn f() {
2823 S +$0 0usize
2824}
2825"#,
2826 );
2827 }
2828
2829 #[test]
2830 fn path_call_multiple_trait_impl() {
2831 check(
2832 r#"
2833trait Trait<T> {
2834 fn f(_: T);
2835}
2836impl Trait<i32> for usize {
2837 fn f(_: i32) {}
2838 //^
2839}
2840impl Trait<i64> for usize {
2841 fn f(_: i64) {}
2842}
2843fn main() {
2844 usize::f$0(0i32);
2845}
2846"#,
2847 );
2848
2849 check(
2850 r#"
2851trait Trait<T> {
2852 fn f(_: T);
2853}
2854impl Trait<i32> for usize {
2855 fn f(_: i32) {}
2856}
2857impl Trait<i64> for usize {
2858 fn f(_: i64) {}
2859 //^
2860}
2861fn main() {
2862 usize::f$0(0i64);
2863}
2864"#,
2865 )
2866 }
2867
2868 #[test]
2869 fn query_impls_in_nearest_block() {
2870 check(
2871 r#"
2872struct S1;
2873impl S1 {
2874 fn e() -> () {}
2875}
2876fn f1() {
2877 struct S1;
2878 impl S1 {
2879 fn e() -> () {}
2880 //^
2881 }
2882 fn f2() {
2883 fn f3() {
2884 S1::e$0();
2885 }
2886 }
2887}
2888"#,
2889 );
2890
2891 check(
2892 r#"
2893struct S1;
2894impl S1 {
2895 fn e() -> () {}
2896}
2897fn f1() {
2898 struct S1;
2899 impl S1 {
2900 fn e() -> () {}
2901 //^
2902 }
2903 fn f2() {
2904 struct S2;
2905 S1::e$0();
2906 }
2907}
2908fn f12() {
2909 struct S1;
2910 impl S1 {
2911 fn e() -> () {}
2912 }
2913}
2914"#,
2915 );
2916
2917 check(
2918 r#"
2919struct S1;
2920impl S1 {
2921 fn e() -> () {}
2922 //^
2923}
2924fn f2() {
2925 struct S2;
2926 S1::e$0();
2927}
2928"#,
2929 );
2930 }
2931
2932 #[test]
2933 fn implicit_format_args() {
2934 check(
2935 r#"
2936//- minicore: fmt
2937fn test() {
2938 let a = "world";
2939 // ^
2940 format_args!("hello {a$0}");
2941}
2942"#,
2943 );
2944 }
2945
2946 #[test]
2947 fn goto_macro_def_from_macro_use() {
2948 check(
2949 r#"
2950//- /main.rs crate:main deps:mac
2951#[macro_use(foo$0)]
2952extern crate mac;
2953
2954//- /mac.rs crate:mac
2955#[macro_export]
2956macro_rules! foo {
2957 //^^^
2958 () => {};
2959}
2960 "#,
2961 );
2962
2963 check(
2964 r#"
2965//- /main.rs crate:main deps:mac
2966#[macro_use(foo, bar$0, baz)]
2967extern crate mac;
2968
2969//- /mac.rs crate:mac
2970#[macro_export]
2971macro_rules! foo {
2972 () => {};
2973}
2974
2975#[macro_export]
2976macro_rules! bar {
2977 //^^^
2978 () => {};
2979}
2980
2981#[macro_export]
2982macro_rules! baz {
2983 () => {};
2984}
2985 "#,
2986 );
2987 }
2988
2989 #[test]
2990 fn goto_shadowed_preludes_in_block_module() {
2991 check(
2992 r#"
2993//- /main.rs crate:main edition:2021 deps:core
2994pub struct S;
2995 //^
2996
2997fn main() {
2998 fn f() -> S$0 {
2999 fn inner() {} // forces a block def map
3000 return S;
3001 }
3002}
3003//- /core.rs crate:core
3004pub mod prelude {
3005 pub mod rust_2021 {
3006 pub enum S;
3007 }
3008}
3009 "#,
3010 );
3011 }
3012
3013 #[test]
3014 fn goto_def_on_return_kw() {
3015 check(
3016 r#"
3017macro_rules! N {
3018 ($i:ident, $x:expr, $blk:expr) => {
3019 for $i in 0..$x {
3020 $blk
3021 }
3022 };
3023}
3024
3025fn main() {
3026 fn f() {
3027 // ^^
3028 N!(i, 5, {
3029 println!("{}", i);
3030 return$0;
3031 });
3032
3033 for i in 1..5 {
3034 return;
3035 }
3036 (|| {
3037 return;
3038 })();
3039 }
3040}
3041"#,
3042 )
3043 }
3044
3045 #[test]
3046 fn goto_def_on_return_kw_in_closure() {
3047 check(
3048 r#"
3049macro_rules! N {
3050 ($i:ident, $x:expr, $blk:expr) => {
3051 for $i in 0..$x {
3052 $blk
3053 }
3054 };
3055}
3056
3057fn main() {
3058 fn f() {
3059 N!(i, 5, {
3060 println!("{}", i);
3061 return;
3062 });
3063
3064 for i in 1..5 {
3065 return;
3066 }
3067 (|| {
3068 // ^
3069 return$0;
3070 })();
3071 }
3072}
3073"#,
3074 )
3075 }
3076
3077 #[test]
3078 fn goto_def_on_break_kw() {
3079 check(
3080 r#"
3081fn main() {
3082 for i in 1..5 {
3083 // ^^^
3084 break$0;
3085 }
3086}
3087"#,
3088 )
3089 }
3090
3091 #[test]
3092 fn goto_def_on_continue_kw() {
3093 check(
3094 r#"
3095fn main() {
3096 for i in 1..5 {
3097 // ^^^
3098 continue$0;
3099 }
3100}
3101"#,
3102 )
3103 }
3104
3105 #[test]
3106 fn goto_def_on_break_kw_for_block() {
3107 check(
3108 r#"
3109fn main() {
3110 'a:{
3111 // ^^^
3112 break$0 'a;
3113 }
3114}
3115"#,
3116 )
3117 }
3118
3119 #[test]
3120 fn goto_def_on_break_with_label() {
3121 check(
3122 r#"
3123fn foo() {
3124 'outer: loop {
3125 // ^^^^
3126 'inner: loop {
3127 'innermost: loop {
3128 }
3129 break$0 'outer;
3130 }
3131 }
3132}
3133"#,
3134 );
3135 }
3136
3137 #[test]
3138 fn label_inside_macro() {
3139 check(
3140 r#"
3141macro_rules! m {
3142 ($s:stmt) => { $s };
3143}
3144
3145fn foo() {
3146 'label: loop {
3147 // ^^^^^^
3148 m!(continue 'label$0);
3149 }
3150}
3151"#,
3152 );
3153 }
3154
3155 #[test]
3156 fn goto_def_on_return_in_try() {
3157 check(
3158 r#"
3159fn main() {
3160 fn f() {
3161 // ^^
3162 try {
3163 return$0;
3164 }
3165
3166 return;
3167 }
3168}
3169"#,
3170 )
3171 }
3172
3173 #[test]
3174 fn goto_def_on_break_in_try() {
3175 check(
3176 r#"
3177fn main() {
3178 for i in 1..100 {
3179 // ^^^
3180 let x: Result<(), ()> = try {
3181 break$0;
3182 };
3183 }
3184}
3185"#,
3186 )
3187 }
3188
3189 #[test]
3190 fn goto_def_on_return_in_async_block() {
3191 check(
3192 r#"
3193fn main() {
3194 async {
3195 // ^^^^^
3196 return$0;
3197 }
3198}
3199"#,
3200 )
3201 }
3202
3203 #[test]
3204 fn goto_def_on_for_kw() {
3205 check(
3206 r#"
3207fn main() {
3208 for$0 i in 1..5 {}
3209 // ^^^
3210}
3211"#,
3212 )
3213 }
3214
3215 #[test]
3216 fn goto_def_on_fn_kw() {
3217 check(
3218 r#"
3219fn main() {
3220 fn$0 foo() {}
3221 // ^^
3222}
3223"#,
3224 )
3225 }
3226
3227 #[test]
3228 fn shadow_builtin_macro() {
3229 check(
3230 r#"
3231//- minicore: column
3232//- /a.rs crate:a
3233#[macro_export]
3234macro_rules! column { () => {} }
3235 // ^^^^^^
3236
3237//- /b.rs crate:b deps:a
3238use a::column;
3239fn foo() {
3240 $0column!();
3241}
3242 "#,
3243 );
3244 }
3245
3246 #[test]
3247 fn issue_18138() {
3248 check(
3249 r#"
3250mod foo {
3251 macro_rules! x {
3252 () => {
3253 pub struct Foo;
3254 // ^^^
3255 };
3256 }
3257 pub(crate) use x as m;
3258}
3259
3260mod bar {
3261 use crate::m;
3262
3263 m!();
3264 // ^^
3265
3266 fn qux() {
3267 Foo$0;
3268 }
3269}
3270
3271mod m {}
3272
3273use foo::m;
3274"#,
3275 );
3276 }
3277
3278 #[test]
3279 fn macro_label_hygiene() {
3280 check(
3281 r#"
3282macro_rules! m {
3283 ($x:stmt) => {
3284 'bar: loop { $x }
3285 };
3286}
3287
3288fn foo() {
3289 'bar: loop {
3290 // ^^^^
3291 m!(continue 'bar$0);
3292 }
3293}
3294"#,
3295 );
3296 }
3297 #[test]
3298 fn into_call_to_from_definition() {
3299 check(
3300 r#"
3301//- minicore: from
3302struct A;
3303
3304struct B;
3305
3306impl From<A> for B {
3307 fn from(value: A) -> Self {
3308 //^^^^
3309 B
3310 }
3311}
3312
3313fn f() {
3314 let a = A;
3315 let b: B = a.into$0();
3316}
3317 "#,
3318 );
3319 }
3320
3321 #[test]
3322 fn into_call_to_from_definition_within_macro() {
3323 check(
3324 r#"
3325//- proc_macros: identity
3326//- minicore: from
3327struct A;
3328
3329struct B;
3330
3331impl From<A> for B {
3332 fn from(value: A) -> Self {
3333 //^^^^
3334 B
3335 }
3336}
3337
3338#[proc_macros::identity]
3339fn f() {
3340 let a = A;
3341 let b: B = a.into$0();
3342}
3343 "#,
3344 );
3345 }
3346
3347 #[test]
3348 fn into_call_to_from_definition_with_trait_bounds() {
3349 check(
3350 r#"
3351//- minicore: from, iterator
3352struct A;
3353
3354impl<T> From<T> for A
3355where
3356 T: IntoIterator<Item = i64>,
3357{
3358 fn from(value: T) -> Self {
3359 //^^^^
3360 A
3361 }
3362}
3363
3364fn f() {
3365 let a: A = [1, 2, 3].into$0();
3366}
3367 "#,
3368 );
3369 }
3370
3371 #[test]
3372 fn goto_into_definition_if_exists() {
3373 check(
3374 r#"
3375//- minicore: from
3376struct A;
3377
3378struct B;
3379
3380impl Into<B> for A {
3381 fn into(self) -> B {
3382 //^^^^
3383 B
3384 }
3385}
3386
3387fn f() {
3388 let a = A;
3389 let b: B = a.into$0();
3390}
3391 "#,
3392 );
3393 }
3394
3395 #[test]
3396 fn try_into_call_to_try_from_definition() {
3397 check(
3398 r#"
3399//- minicore: from
3400struct A;
3401
3402struct B;
3403
3404impl TryFrom<A> for B {
3405 type Error = String;
3406
3407 fn try_from(value: A) -> Result<Self, Self::Error> {
3408 //^^^^^^^^
3409 Ok(B)
3410 }
3411}
3412
3413fn f() {
3414 let a = A;
3415 let b: Result<B, _> = a.try_into$0();
3416}
3417 "#,
3418 );
3419 }
3420
3421 #[test]
3422 fn goto_try_into_definition_if_exists() {
3423 check(
3424 r#"
3425//- minicore: from
3426struct A;
3427
3428struct B;
3429
3430impl TryInto<B> for A {
3431 type Error = String;
3432
3433 fn try_into(self) -> Result<B, Self::Error> {
3434 //^^^^^^^^
3435 Ok(B)
3436 }
3437}
3438
3439fn f() {
3440 let a = A;
3441 let b: Result<B, _> = a.try_into$0();
3442}
3443 "#,
3444 );
3445 }
3446
3447 #[test]
3448 fn parse_call_to_from_str_definition() {
3449 check(
3450 r#"
3451//- minicore: from, str
3452struct A;
3453impl FromStr for A {
3454 type Error = String;
3455 fn from_str(value: &str) -> Result<Self, Self::Error> {
3456 //^^^^^^^^
3457 Ok(A)
3458 }
3459}
3460fn f() {
3461 let a: Result<A, _> = "aaaaaa".parse$0();
3462}
3463 "#,
3464 );
3465 }
3466
3467 #[test]
3468 fn to_string_call_to_display_definition() {
3469 check(
3470 r#"
3471//- minicore:fmt
3472//- /alloc.rs crate:alloc
3473pub mod string {
3474 pub struct String;
3475 pub trait ToString {
3476 fn to_string(&self) -> String;
3477 }
3478
3479 impl<T: core::fmt::Display> ToString for T {
3480 fn to_string(&self) -> String { String }
3481 }
3482}
3483//- /lib.rs crate:lib deps:alloc
3484use alloc::string::ToString;
3485struct A;
3486impl core::fmt::Display for A {
3487 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {}
3488 // ^^^
3489}
3490fn f() {
3491 A.to_string$0();
3492}
3493 "#,
3494 );
3495 }
3496
3497 #[test]
3498 fn use_inside_body() {
3499 check(
3500 r#"
3501fn main() {
3502 mod nice_module {
3503 pub(super) struct NiceStruct;
3504 // ^^^^^^^^^^
3505 }
3506
3507 use nice_module::NiceStruct$0;
3508
3509 let _ = NiceStruct;
3510}
3511 "#,
3512 );
3513 }
3514
3515 #[test]
3516 fn shadow_builtin_type_by_module() {
3517 check(
3518 r#"
3519mod Foo{
3520pub mod str {
3521 // ^^^
3522 pub fn foo() {}
3523}
3524}
3525
3526fn main() {
3527 use Foo::str;
3528 let s = st$0r::foo();
3529}
3530"#,
3531 );
3532 }
3533
3534 #[test]
3535 fn not_goto_module_because_str_is_builtin_type() {
3536 check(
3537 r#"
3538mod str {
3539pub fn foo() {}
3540}
3541
3542fn main() {
3543 let s = st$0r::f();
3544}
3545"#,
3546 );
3547 }
3548
3549 #[test]
3550 fn struct_shadow_by_module() {
3551 check(
3552 r#"
3553mod foo {
3554 pub mod bar {
3555 // ^^^
3556 pub type baz = usize;
3557 }
3558}
3559struct bar;
3560fn main() {
3561 use foo::bar;
3562 let x: ba$0r::baz = 5;
3563
3564}
3565"#,
3566 );
3567 }
3568
3569 #[test]
3570 fn type_alias_shadow_by_module() {
3571 check(
3572 r#"
3573mod foo {
3574 pub mod bar {
3575 // ^^^
3576 pub fn baz() {}
3577 }
3578}
3579
3580trait Qux {}
3581
3582fn item<bar: Qux>() {
3583 use foo::bar;
3584 ba$0r::baz();
3585}
3586}
3587"#,
3588 );
3589
3590 check(
3591 r#"
3592mod foo {
3593 pub mod bar {
3594 // ^^^
3595 pub fn baz() {}
3596 }
3597}
3598
3599fn item<bar>(x: bar) {
3600 use foo::bar;
3601 let x: bar$0 = x;
3602}
3603"#,
3604 );
3605 }
3606
3607 #[test]
3608 fn trait_shadow_by_module() {
3609 check(
3610 r#"
3611pub mod foo {
3612 pub mod Bar {}
3613 // ^^^
3614}
3615
3616trait Bar {}
3617
3618fn main() {
3619 use foo::Bar;
3620 fn f<Qux: B$0ar>() {}
3621}
3622 "#,
3623 );
3624 }
3625
3626 #[test]
3627 fn const_shadow_by_module() {
3628 check(
3629 r#"
3630pub mod foo {
3631 pub struct u8 {}
3632 pub mod bar {
3633 pub mod u8 {}
3634 }
3635}
3636
3637fn main() {
3638 use foo::u8;
3639 {
3640 use foo::bar::u8;
3641
3642 fn f1<const N: u$08>() {}
3643 }
3644 fn f2<const N: u8>() {}
3645}
3646"#,
3647 );
3648
3649 check(
3650 r#"
3651pub mod foo {
3652 pub struct u8 {}
3653 // ^^
3654 pub mod bar {
3655 pub mod u8 {}
3656 }
3657}
3658
3659fn main() {
3660 use foo::u8;
3661 {
3662 use foo::bar::u8;
3663
3664 fn f1<const N: u8>() {}
3665 }
3666 fn f2<const N: u$08>() {}
3667}
3668"#,
3669 );
3670
3671 check(
3672 r#"
3673pub mod foo {
3674 pub struct buz {}
3675 pub mod bar {
3676 pub mod buz {}
3677 // ^^^
3678 }
3679}
3680
3681fn main() {
3682 use foo::buz;
3683 {
3684 use foo::bar::buz;
3685
3686 fn f1<const N: buz$0>() {}
3687 }
3688}
3689"#,
3690 );
3691 }
3692
3693 #[test]
3694 fn offset_of() {
3695 check(
3696 r#"
3697//- minicore: offset_of
3698struct Foo {
3699 field: i32,
3700 // ^^^^^
3701}
3702
3703fn foo() {
3704 let _ = core::mem::offset_of!(Foo, fiel$0d);
3705}
3706 "#,
3707 );
3708
3709 check(
3710 r#"
3711//- minicore: offset_of
3712struct Bar(Foo);
3713struct Foo {
3714 field: i32,
3715 // ^^^^^
3716}
3717
3718fn foo() {
3719 let _ = core::mem::offset_of!(Bar, 0.fiel$0d);
3720}
3721 "#,
3722 );
3723
3724 check(
3725 r#"
3726//- minicore: offset_of
3727struct Bar(Baz);
3728enum Baz {
3729 Abc(Foo),
3730 None,
3731}
3732struct Foo {
3733 field: i32,
3734 // ^^^^^
3735}
3736
3737fn foo() {
3738 let _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d);
3739}
3740 "#,
3741 );
3742
3743 check(
3744 r#"
3745//- minicore: offset_of
3746struct Bar(Baz);
3747enum Baz {
3748 Abc(Foo),
3749 // ^^^
3750 None,
3751}
3752struct Foo {
3753 field: i32,
3754}
3755
3756fn foo() {
3757 let _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field);
3758}
3759 "#,
3760 );
3761 }
3762
3763 #[test]
3764 fn goto_def_for_match_keyword() {
3765 check(
3766 r#"
3767fn main() {
3768 match$0 0 {
3769 // ^^^^^
3770 0 => {},
3771 _ => {},
3772 }
3773}
3774"#,
3775 );
3776 }
3777
3778 #[test]
3779 fn goto_def_for_match_arm_fat_arrow() {
3780 check(
3781 r#"
3782fn main() {
3783 match 0 {
3784 0 =>$0 {},
3785 // ^^
3786 _ => {},
3787 }
3788}
3789"#,
3790 );
3791 }
3792
3793 #[test]
3794 fn goto_def_for_if_keyword() {
3795 check(
3796 r#"
3797fn main() {
3798 if$0 true {
3799 // ^^
3800 ()
3801 }
3802}
3803"#,
3804 );
3805 }
3806
3807 #[test]
3808 fn goto_def_for_match_nested_in_if() {
3809 check(
3810 r#"
3811fn main() {
3812 if true {
3813 match$0 0 {
3814 // ^^^^^
3815 0 => {},
3816 _ => {},
3817 }
3818 }
3819}
3820"#,
3821 );
3822 }
3823
3824 #[test]
3825 fn goto_def_for_multiple_match_expressions() {
3826 check(
3827 r#"
3828fn main() {
3829 match 0 {
3830 0 => {},
3831 _ => {},
3832 };
3833
3834 match$0 1 {
3835 // ^^^^^
3836 1 => {},
3837 _ => {},
3838 }
3839}
3840"#,
3841 );
3842 }
3843
3844 #[test]
3845 fn goto_def_for_nested_match_expressions() {
3846 check(
3847 r#"
3848fn main() {
3849 match 0 {
3850 0 => match$0 1 {
3851 // ^^^^^
3852 1 => {},
3853 _ => {},
3854 },
3855 _ => {},
3856 }
3857}
3858"#,
3859 );
3860 }
3861
3862 #[test]
3863 fn goto_def_for_if_else_chains() {
3864 check(
3865 r#"
3866fn main() {
3867 if true {
3868 // ^^
3869 ()
3870 } else if$0 false {
3871 ()
3872 } else {
3873 ()
3874 }
3875}
3876"#,
3877 );
3878 }
3879
3880 #[test]
3881 fn goto_def_for_match_with_guards() {
3882 check(
3883 r#"
3884fn main() {
3885 match 42 {
3886 x if x > 0 =>$0 {},
3887 // ^^
3888 _ => {},
3889 }
3890}
3891"#,
3892 );
3893 }
3894
3895 #[test]
3896 fn goto_def_for_match_with_macro_arm() {
3897 check(
3898 r#"
3899macro_rules! arm {
3900 () => { 0 => {} };
3901}
3902
3903fn main() {
3904 match$0 0 {
3905 // ^^^^^
3906 arm!(),
3907 _ => {},
3908 }
3909}
3910"#,
3911 );
3912 }
3913
3914 #[test]
3915 fn goto_const_from_match_pat_with_tuple_struct() {
3916 check(
3917 r#"
3918struct Tag(u8);
3919struct Path {}
3920
3921const Path: u8 = 0;
3922 // ^^^^
3923fn main() {
3924 match Tag(Path) {
3925 Tag(Path$0) => {}
3926 _ => {}
3927 }
3928}
3929
3930"#,
3931 );
3932 }
3933
3934 #[test]
3935 fn goto_const_from_match_pat() {
3936 check(
3937 r#"
3938type T1 = u8;
3939const T1: u8 = 0;
3940 // ^^
3941fn main() {
3942 let x = 0;
3943 match x {
3944 T1$0 => {}
3945 _ => {}
3946 }
3947}
3948"#,
3949 );
3950 }
3951
3952 #[test]
3953 fn goto_struct_from_match_pat() {
3954 check(
3955 r#"
3956struct T1;
3957 // ^^
3958fn main() {
3959 let x = 0;
3960 match x {
3961 T1$0 => {}
3962 _ => {}
3963 }
3964}
3965"#,
3966 );
3967 }
3968
3969 #[test]
3970 fn no_goto_trait_from_match_pat() {
3971 check(
3972 r#"
3973trait T1 {}
3974fn main() {
3975 let x = 0;
3976 match x {
3977 T1$0 => {}
3978 // ^^
3979 _ => {}
3980 }
3981}
3982"#,
3983 );
3984 }
3985
3986 #[test]
3987 fn goto_builtin_type() {
3988 check(
3989 r#"
3990//- /main.rs crate:main deps:std
3991const _: &str$0 = ""; }
3992
3993//- /libstd.rs crate:std
3994mod prim_str {}
3995// ^^^^^^^^
3996"#,
3997 );
3998 }
3999
4000 #[test]
4001 fn ra_fixture() {
4002 check(
4003 r##"
4004fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
4005
4006fn foo() {
4007 fixture(r#"
4008fn foo() {}
4009// ^^^
4010fn bar() {
4011 f$0oo();
4012}
4013 "#)
4014}
4015 "##,
4016 );
4017 }
4018
4019 #[test]
4020 fn regression_20038() {
4021 check(
4022 r#"
4023//- minicore: clone, fn
4024struct Map<Fut, F>(Fut, F);
4025
4026struct InspectFn<F>(F);
4027
4028trait FnOnce1<A> {
4029 type Output;
4030}
4031
4032trait Future1 {
4033 type Output;
4034}
4035
4036trait FusedFuture1: Future1 {
4037 fn is_terminated(&self) -> bool;
4038 //^^^^^^^^^^^^^
4039}
4040
4041impl<T, A, R> FnOnce1<A> for T
4042where
4043 T: FnOnce(A) -> R,
4044{
4045 type Output = R;
4046}
4047
4048impl<F, A> FnOnce1<A> for InspectFn<F>
4049where
4050 F: for<'a> FnOnce1<&'a A, Output = ()>,
4051{
4052 type Output = A;
4053}
4054
4055impl<Fut, F, T> Future1 for Map<Fut, F>
4056where
4057 Fut: Future1,
4058 F: FnOnce1<Fut::Output, Output = T>,
4059{
4060 type Output = T;
4061}
4062
4063impl<Fut, F, T> FusedFuture1 for Map<Fut, F>
4064where
4065 Fut: Future1,
4066 F: FnOnce1<Fut::Output, Output = T>,
4067{
4068 fn is_terminated(&self) -> bool {
4069 false
4070 }
4071}
4072
4073fn overflows<Fut, F>(inner: &Map<Fut, InspectFn<F>>)
4074where
4075 Map<Fut, InspectFn<F>>: FusedFuture1
4076{
4077 let _x = inner.is_terminated$0();
4078}
4079"#,
4080 )
4081 }
4082}