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