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