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