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