Skip to main content

hir/
semantics.rs

1//! See `Semantics`.
2
3mod child_by_source;
4mod source_to_def;
5
6use std::{
7    cell::RefCell,
8    convert::Infallible,
9    fmt, iter, mem,
10    ops::{self, ControlFlow, Not},
11};
12
13use base_db::{FxIndexSet, all_crates, toolchain_channel};
14use either::Either;
15use hir_def::{
16    BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, MacroId,
17    StructId, TraitId, VariantId,
18    attrs::parse_extra_crate_attrs,
19    expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path},
20    hir::{BindingId, Expr, ExprId, ExprOrPatId, Unsafe},
21    nameres::{ModuleOrigin, crate_def_map},
22    resolver::{self, HasResolver, Resolver, TypeNs, ValueNs},
23    type_ref::Mutability,
24};
25use hir_expand::{
26    EditionedFileId, ExpandResult, FileRange, HirFileId, InMacroFile, MacroCallId,
27    attrs::AstPathExt,
28    builtin::{BuiltinFnLikeExpander, EagerExpander},
29    files::{FileRangeWrapper, HirFileRange, InRealFile},
30    mod_path::{ModPath, PathKind},
31    name::AsName,
32};
33use hir_ty::{
34    InferBodyId, InferenceResult, LoweringMode,
35    db::AnonConstId,
36    diagnostics::unsafe_operations,
37    infer_query_with_inspect,
38    next_solver::{
39        AnyImplId, DbInterner,
40        format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
41    },
42};
43use intern::{Interned, Symbol, sym};
44use itertools::Itertools;
45use rustc_hash::{FxHashMap, FxHashSet};
46use smallvec::{SmallVec, smallvec};
47use span::{FileId, SyntaxContext};
48use stdx::{TupleExt, always};
49use syntax::{
50    AstNode, AstPtr, AstToken, Direction, SmolStr, SmolStrBuilder, SyntaxElement, SyntaxKind,
51    SyntaxNode, SyntaxNodePtr, SyntaxToken, T, TextRange, TextSize,
52    algo::skip_trivia_token,
53    ast::{self, HasAttrs as _, HasGenericParams},
54};
55
56use crate::{
57    Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
58    ConstParam, Crate, DeriveHelper, Enum, EnumVariant, ExpressionStoreOwner, Field, Function,
59    GenericSubstitution, HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam,
60    Local, Macro, Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule,
61    Trait, TupleField, Type, TypeAlias, TypeParam, Union, Variant,
62    db::HirDatabase,
63    semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
64    source_analyzer::{SourceAnalyzer, resolve_hir_path},
65};
66
67const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(());
68
69#[derive(Debug, Copy, Clone, PartialEq, Eq)]
70pub enum PathResolution<'db> {
71    /// An item
72    Def(ModuleDef),
73    /// A local binding (only value namespace)
74    Local(Local<'db>),
75    /// A type parameter
76    TypeParam(TypeParam),
77    /// A const parameter
78    ConstParam(ConstParam),
79    SelfType(Impl),
80    BuiltinAttr(BuiltinAttr),
81    ToolModule(ToolModule),
82    DeriveHelper(DeriveHelper),
83}
84
85impl<'db> PathResolution<'db> {
86    pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
87        match self {
88            PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())),
89            PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
90                Some(TypeNs::BuiltinType((*builtin).into()))
91            }
92            PathResolution::Def(
93                ModuleDef::Const(_)
94                | ModuleDef::EnumVariant(_)
95                | ModuleDef::Macro(_)
96                | ModuleDef::Function(_)
97                | ModuleDef::Module(_)
98                | ModuleDef::Static(_)
99                | ModuleDef::Trait(_),
100            ) => None,
101            PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
102                Some(TypeNs::TypeAliasId((*alias).into()))
103            }
104            PathResolution::BuiltinAttr(_)
105            | PathResolution::ToolModule(_)
106            | PathResolution::Local(_)
107            | PathResolution::DeriveHelper(_)
108            | PathResolution::ConstParam(_) => None,
109            PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
110            PathResolution::SelfType(impl_def) => match impl_def.id {
111                AnyImplId::ImplId(id) => Some(TypeNs::SelfType(id)),
112                AnyImplId::BuiltinDeriveImplId(_) => None,
113            },
114        }
115    }
116}
117
118#[derive(Debug, Copy, Clone, PartialEq, Eq)]
119pub struct PathResolutionPerNs<'db> {
120    pub type_ns: Option<PathResolution<'db>>,
121    pub value_ns: Option<PathResolution<'db>>,
122    pub macro_ns: Option<PathResolution<'db>>,
123}
124
125impl<'db> PathResolutionPerNs<'db> {
126    pub fn new(
127        type_ns: Option<PathResolution<'db>>,
128        value_ns: Option<PathResolution<'db>>,
129        macro_ns: Option<PathResolution<'db>>,
130    ) -> Self {
131        PathResolutionPerNs { type_ns, value_ns, macro_ns }
132    }
133    pub fn any(&self) -> Option<PathResolution<'db>> {
134        self.type_ns.or(self.value_ns).or(self.macro_ns)
135    }
136}
137
138#[derive(Debug)]
139pub struct TypeInfo<'db> {
140    /// The original type of the expression or pattern.
141    pub original: Type<'db>,
142    /// The adjusted type, if an adjustment happened.
143    pub adjusted: Option<Type<'db>>,
144}
145
146impl<'db> TypeInfo<'db> {
147    pub fn original(self) -> Type<'db> {
148        self.original
149    }
150
151    pub fn has_adjustment(&self) -> bool {
152        self.adjusted.is_some()
153    }
154
155    /// The adjusted type, or the original in case no adjustments occurred.
156    pub fn adjusted(self) -> Type<'db> {
157        self.adjusted.unwrap_or(self.original)
158    }
159}
160
161/// Primary API to get semantic information, like types, from syntax trees.
162pub struct Semantics<'db, DB: ?Sized> {
163    pub db: &'db DB,
164    imp: SemanticsImpl<'db>,
165}
166
167type DefWithoutBodyWithAnonConsts = Either<GenericDefId, VariantId>;
168type ExprToAnonConst<'db> = FxHashMap<ExprId, AnonConstId<'db>>;
169type DefAnonConstsMap<'db> = FxHashMap<DefWithoutBodyWithAnonConsts, ExprToAnonConst<'db>>;
170
171pub struct SemanticsImpl<'db> {
172    pub db: &'db dyn HirDatabase,
173    s2d_cache: RefCell<SourceToDefCache<'db>>,
174    /// MacroCall to its expansion's MacroCallId cache
175    macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>,
176    /// All anon consts defined by a *signature* (not a body).
177    signature_anon_consts_cache: RefCell<DefAnonConstsMap<'db>>,
178}
179
180impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> {
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        write!(f, "Semantics {{ ... }}")
183    }
184}
185
186impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
187    type Target = SemanticsImpl<'db>;
188
189    fn deref(&self) -> &Self::Target {
190        &self.imp
191    }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
195pub enum LintAttr {
196    Allow,
197    Expect,
198    Warn,
199    Deny,
200    Forbid,
201}
202
203// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
204// find actual use within the rust-analyzer project itself, it exists to enable the use
205// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
206impl Semantics<'_, dyn HirDatabase> {
207    /// Creates an instance that's weakly coupled to its underlying database type.
208    pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> {
209        let impl_ = SemanticsImpl::new(db);
210        Semantics { db, imp: impl_ }
211    }
212}
213
214impl<DB: HirDatabase> Semantics<'_, DB> {
215    /// Creates an instance that's strongly coupled to its underlying database type.
216    pub fn new(db: &DB) -> Semantics<'_, DB> {
217        let impl_ = SemanticsImpl::new(db);
218        Semantics { db, imp: impl_ }
219    }
220}
221
222// Note: We take `DB` as `?Sized` here in order to support type-erased
223// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
224impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
225    pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
226        self.imp.find_file(syntax_node).file_id
227    }
228
229    pub fn token_ancestors_with_macros(
230        &self,
231        token: SyntaxToken,
232    ) -> impl Iterator<Item = SyntaxNode> + '_ {
233        token.parent().into_iter().flat_map(move |it| self.ancestors_with_macros(it))
234    }
235
236    /// Find an AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
237    /// search up until it is of the target AstNode type
238    pub fn find_node_at_offset_with_macros<N: AstNode>(
239        &self,
240        node: &SyntaxNode,
241        offset: TextSize,
242    ) -> Option<N> {
243        self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
244    }
245
246    /// Find an AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
247    /// descend it and find again
248    // FIXME: Rethink this API
249    pub fn find_node_at_offset_with_descend<N: AstNode>(
250        &self,
251        node: &SyntaxNode,
252        offset: TextSize,
253    ) -> Option<N> {
254        self.imp.descend_node_at_offset(node, offset).flatten().find_map(N::cast)
255    }
256
257    /// Find an AstNode by offset inside SyntaxNode, if it is inside an attribute macro call,
258    /// descend it and find again
259    // FIXME: Rethink this API
260    pub fn find_nodes_at_offset_with_descend<'slf, N: AstNode + 'slf>(
261        &'slf self,
262        node: &SyntaxNode,
263        offset: TextSize,
264    ) -> impl Iterator<Item = N> + 'slf {
265        self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
266    }
267
268    // FIXME: Rethink this API
269    pub fn find_namelike_at_offset_with_descend<'slf>(
270        &'slf self,
271        node: &SyntaxNode,
272        offset: TextSize,
273    ) -> impl Iterator<Item = ast::NameLike> + 'slf {
274        node.token_at_offset(offset)
275            .map(move |token| self.descend_into_macros_no_opaque(token, true))
276            .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
277            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
278            // See algo::ancestors_at_offset, which uses the same approach
279            .kmerge_by(|left, right| left.text_range().len().lt(&right.text_range().len()))
280            .filter_map(ast::NameLike::cast)
281    }
282
283    pub fn lint_attrs(
284        &self,
285        file_id: FileId,
286        krate: Crate,
287        item: ast::AnyHasAttrs,
288    ) -> impl DoubleEndedIterator<Item = (LintAttr, SmolStr)> {
289        let mut cfg_options = None;
290        let cfg_options = || *cfg_options.get_or_insert_with(|| krate.id.cfg_options(self.db));
291
292        let is_crate_root = file_id == krate.root_file(self.imp.db);
293        let is_source_file = ast::SourceFile::can_cast(item.syntax().kind());
294        let extra_crate_attrs = (is_crate_root && is_source_file)
295            .then(|| {
296                parse_extra_crate_attrs(self.imp.db, krate.id)
297                    .into_iter()
298                    .flat_map(|src| src.attrs())
299            })
300            .into_iter()
301            .flatten();
302
303        let mut result = Vec::new();
304        hir_expand::attrs::expand_cfg_attr::<Infallible>(
305            extra_crate_attrs.chain(ast::attrs_including_inner(&item)),
306            cfg_options,
307            |attr, _| {
308                let ast::Meta::TokenTreeMeta(attr) = attr else {
309                    return ControlFlow::Continue(());
310                };
311                let (Some(segment), Some(tt)) = (attr.path().as_one_segment(), attr.token_tree())
312                else {
313                    return ControlFlow::Continue(());
314                };
315                let lint_attr = match &*segment {
316                    "allow" => LintAttr::Allow,
317                    "expect" => LintAttr::Expect,
318                    "warn" => LintAttr::Warn,
319                    "deny" => LintAttr::Deny,
320                    "forbid" => LintAttr::Forbid,
321                    _ => return ControlFlow::Continue(()),
322                };
323                let mut lint = SmolStrBuilder::new();
324                for token in
325                    tt.syntax().children_with_tokens().filter_map(SyntaxElement::into_token)
326                {
327                    match token.kind() {
328                        T![:] | T![::] => lint.push_str(token.text()),
329                        kind if kind.is_any_identifier() => lint.push_str(token.text()),
330                        T![,] => {
331                            let lint = mem::replace(&mut lint, SmolStrBuilder::new()).finish();
332                            if !lint.is_empty() {
333                                result.push((lint_attr, lint));
334                            }
335                        }
336                        _ => {}
337                    }
338                }
339                let lint = lint.finish();
340                if !lint.is_empty() {
341                    result.push((lint_attr, lint));
342                }
343
344                ControlFlow::Continue(())
345            },
346        );
347        result.into_iter()
348    }
349
350    pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
351        self.imp.resolve_range_pat(range_pat).map(Struct::from)
352    }
353
354    pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
355        self.imp.resolve_range_expr(range_expr).map(Struct::from)
356    }
357
358    pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
359        self.imp.resolve_await_to_poll(await_expr)
360    }
361
362    pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
363        self.imp.resolve_prefix_expr(prefix_expr)
364    }
365
366    pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
367        self.imp.resolve_index_expr(index_expr)
368    }
369
370    pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
371        self.imp.resolve_bin_expr(bin_expr)
372    }
373
374    pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
375        self.imp.resolve_try_expr(try_expr)
376    }
377
378    pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<Variant> {
379        self.imp.resolve_variant(record_lit).map(Variant::from)
380    }
381
382    pub fn file_to_module_def(&self, file: impl Into<FileId>) -> Option<Module> {
383        self.imp.file_to_module_defs(file.into()).next()
384    }
385
386    pub fn file_to_module_defs(&self, file: impl Into<FileId>) -> impl Iterator<Item = Module> {
387        self.imp.file_to_module_defs(file.into())
388    }
389
390    pub fn hir_file_to_module_def(&self, file: impl Into<HirFileId>) -> Option<Module> {
391        self.imp.hir_file_to_module_defs(file.into()).next()
392    }
393
394    pub fn hir_file_to_module_defs(
395        &self,
396        file: impl Into<HirFileId>,
397    ) -> impl Iterator<Item = Module> {
398        self.imp.hir_file_to_module_defs(file.into())
399    }
400
401    pub fn is_nightly(&self, krate: Crate) -> bool {
402        let toolchain = toolchain_channel(self.db.as_dyn_database(), krate.into());
403        // `toolchain == None` means we're in some detached files. Since we have no information on
404        // the toolchain being used, let's just allow unstable items to be listed.
405        matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None)
406    }
407
408    pub fn to_adt_def(&self, a: &ast::Adt) -> Option<Adt> {
409        self.imp.to_def(a)
410    }
411
412    pub fn to_const_def(&self, c: &ast::Const) -> Option<Const> {
413        self.imp.to_def(c)
414    }
415
416    pub fn to_enum_def(&self, e: &ast::Enum) -> Option<Enum> {
417        self.imp.to_def(e)
418    }
419
420    pub fn to_enum_variant_def(&self, v: &ast::Variant) -> Option<EnumVariant> {
421        self.imp.to_def(v)
422    }
423
424    pub fn to_fn_def(&self, f: &ast::Fn) -> Option<Function> {
425        self.imp.to_def(f)
426    }
427
428    pub fn to_impl_def(&self, i: &ast::Impl) -> Option<Impl> {
429        self.imp.to_def(i)
430    }
431
432    pub fn to_macro_def(&self, m: &ast::Macro) -> Option<Macro> {
433        self.imp.to_def(m)
434    }
435
436    pub fn to_module_def(&self, m: &ast::Module) -> Option<Module> {
437        self.imp.to_def(m)
438    }
439
440    pub fn to_static_def(&self, s: &ast::Static) -> Option<Static> {
441        self.imp.to_def(s)
442    }
443
444    pub fn to_struct_def(&self, s: &ast::Struct) -> Option<Struct> {
445        self.imp.to_def(s)
446    }
447
448    pub fn to_trait_def(&self, t: &ast::Trait) -> Option<Trait> {
449        self.imp.to_def(t)
450    }
451
452    pub fn to_type_alias_def(&self, t: &ast::TypeAlias) -> Option<TypeAlias> {
453        self.imp.to_def(t)
454    }
455
456    pub fn to_union_def(&self, u: &ast::Union) -> Option<Union> {
457        self.imp.to_def(u)
458    }
459}
460
461impl<'db> SemanticsImpl<'db> {
462    fn new(db: &'db dyn HirDatabase) -> Self {
463        SemanticsImpl {
464            db,
465            s2d_cache: Default::default(),
466            macro_call_cache: Default::default(),
467            signature_anon_consts_cache: Default::default(),
468        }
469    }
470
471    pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile {
472        let hir_file_id = file_id.into();
473        let tree = file_id.parse(self.db).tree();
474        self.cache(tree.syntax().clone(), hir_file_id);
475        tree
476    }
477
478    /// If not crate is found for the file, try to return the last crate in topological order.
479    pub fn first_crate(&self, file: FileId) -> Option<Crate> {
480        match self.file_to_module_defs(file).next() {
481            Some(module) => Some(module.krate(self.db)),
482            None => all_crates(self.db).last().copied().map(Into::into),
483        }
484    }
485
486    pub fn attach_first_edition_opt(&self, file: FileId) -> Option<EditionedFileId> {
487        let krate = self.file_to_module_defs(file).next()?.krate(self.db);
488        Some(EditionedFileId::new(self.db, file, krate.edition(self.db)))
489    }
490
491    pub fn attach_first_edition(&self, file: FileId) -> EditionedFileId {
492        self.attach_first_edition_opt(file)
493            .unwrap_or_else(|| EditionedFileId::current_edition(self.db, file))
494    }
495
496    pub fn parse_guess_edition(&self, file_id: FileId) -> ast::SourceFile {
497        let file_id = self.attach_first_edition(file_id);
498
499        let tree = file_id.parse(self.db).tree();
500        self.cache(tree.syntax().clone(), file_id.into());
501        tree
502    }
503
504    pub fn adjust_edition(&self, file_id: HirFileId) -> HirFileId {
505        if let Some(editioned_file_id) = file_id.file_id() {
506            self.attach_first_edition_opt(editioned_file_id.file_id(self.db))
507                .map_or(file_id, Into::into)
508        } else {
509            file_id
510        }
511    }
512
513    pub fn find_parent_file(&self, file_id: HirFileId) -> Option<InFile<SyntaxNode>> {
514        match file_id {
515            HirFileId::FileId(file_id) => {
516                let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
517                let def_map = crate_def_map(self.db, module.krate(self.db).id);
518                match def_map[module.id].origin {
519                    ModuleOrigin::CrateRoot { .. } => None,
520                    ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
521                        let file_id = declaration_tree_id.file_id();
522                        let in_file = InFile::new(file_id, declaration);
523                        let node = in_file.to_node(self.db);
524                        let root = node.syntax().tree_top();
525                        self.cache(root, file_id);
526                        Some(in_file.with_value(node.syntax().clone()))
527                    }
528                    _ => unreachable!("FileId can only belong to a file module"),
529                }
530            }
531            HirFileId::MacroFile(macro_file) => {
532                let node = macro_file.loc(self.db).to_node(self.db);
533                let root = node.value.tree_top();
534                self.cache(root, node.file_id);
535                Some(node)
536            }
537        }
538    }
539
540    /// Returns the `SyntaxNode` of the module. If this is a file module, returns
541    /// the `SyntaxNode` of the *definition* file, not of the *declaration*.
542    pub fn module_definition_node(&self, module: Module) -> InFile<SyntaxNode> {
543        let def_map = module.id.def_map(self.db);
544        let definition = def_map[module.id].origin.definition_source(self.db);
545        let definition = definition.map(|it| it.node());
546        let root_node = definition.value.tree_top();
547        self.cache(root_node, definition.file_id);
548        definition
549    }
550
551    pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
552        let node = file_id.parse_or_expand(self.db);
553        self.cache(node.clone(), file_id);
554        node
555    }
556
557    pub fn to_node_syntax(&self, ptr: InFile<SyntaxNodePtr>) -> SyntaxNode {
558        ptr.value.to_node(&self.parse_or_expand(ptr.file_id))
559    }
560
561    pub fn to_node<N: AstNode>(&self, ptr: InFile<AstPtr<N>>) -> N {
562        ptr.value.to_node(&self.parse_or_expand(ptr.file_id))
563    }
564
565    pub fn expand(&self, file_id: MacroCallId) -> ExpandResult<SyntaxNode> {
566        let res = file_id.parse_macro_expansion(self.db).as_ref().map(|it| it.0.syntax_node());
567        self.cache(res.value.clone(), file_id.into());
568        res
569    }
570
571    pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option<InFile<SyntaxNode>> {
572        let file_id = self.to_def(macro_call)?;
573        let node = self.parse_or_expand(file_id.into());
574        Some(InFile::new(file_id.into(), node))
575    }
576
577    /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy
578    /// expansions.
579    pub fn expand_allowed_builtins(
580        &self,
581        macro_call: &ast::MacroCall,
582    ) -> Option<ExpandResult<SyntaxNode>> {
583        let file_id = self.to_def(macro_call)?;
584        let macro_call = file_id.loc(self.db);
585
586        let skip = matches!(
587            macro_call.def.kind,
588            hir_expand::MacroDefKind::BuiltIn(
589                _,
590                BuiltinFnLikeExpander::Column
591                    | BuiltinFnLikeExpander::File
592                    | BuiltinFnLikeExpander::ModulePath
593                    | BuiltinFnLikeExpander::Asm
594                    | BuiltinFnLikeExpander::GlobalAsm
595                    | BuiltinFnLikeExpander::NakedAsm
596                    | BuiltinFnLikeExpander::LogSyntax
597                    | BuiltinFnLikeExpander::TraceMacros
598                    | BuiltinFnLikeExpander::FormatArgs
599                    | BuiltinFnLikeExpander::FormatArgsNl
600                    | BuiltinFnLikeExpander::ConstFormatArgs,
601            ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError)
602        );
603        if skip {
604            // these macros expand to custom builtin syntax and/or dummy things, no point in
605            // showing these to the user
606            return None;
607        }
608
609        let node = self.expand(file_id);
610        Some(node)
611    }
612
613    /// If `item` has an attribute macro attached to it, expands it.
614    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<ExpandResult<InFile<SyntaxNode>>> {
615        let src = self.wrap_node_infile(item.clone());
616        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?;
617        Some(self.expand(macro_call_id).map(|it| InFile::new(macro_call_id.into(), it)))
618    }
619
620    pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Meta) -> Option<SyntaxNode> {
621        let adt = attr.parent_attr()?.syntax().parent().and_then(ast::Adt::cast)?;
622        let src = self.wrap_node_infile(attr.clone());
623        let call_id = self.with_ctx(|ctx| {
624            ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
625        })?;
626        Some(self.parse_or_expand(call_id.into()))
627    }
628
629    pub fn resolve_derive_macro(&self, attr: &ast::Meta) -> Option<Vec<Option<Macro>>> {
630        let calls = self.derive_macro_calls(attr)?;
631        self.with_ctx(|ctx| {
632            Some(
633                calls
634                    .into_iter()
635                    .map(|call| {
636                        let call = call?;
637                        match call {
638                            Either::Left(call) => {
639                                macro_call_to_macro_id(ctx, call).map(|id| Macro { id })
640                            }
641                            Either::Right(call) => {
642                                let call = call.loc(self.db);
643                                let krate = call.krate(self.db);
644                                let lang_items = hir_def::lang_item::lang_items(self.db, krate);
645                                call.trait_.derive_macro(lang_items).map(|id| Macro { id })
646                            }
647                        }
648                    })
649                    .collect(),
650            )
651        })
652    }
653
654    pub fn expand_derive_macro(
655        &self,
656        attr: &ast::Meta,
657    ) -> Option<Vec<Option<ExpandResult<SyntaxNode>>>> {
658        let res: Vec<_> = self
659            .derive_macro_calls(attr)?
660            .into_iter()
661            .map(|call| {
662                let file_id = call?.left()?;
663                let ExpandResult { value, err } = file_id.parse_macro_expansion(self.db);
664                let root_node = value.0.syntax_node();
665                self.cache(root_node.clone(), file_id.into());
666                Some(ExpandResult { value: root_node, err: err.clone() })
667            })
668            .collect();
669        Some(res)
670    }
671
672    fn derive_macro_calls(
673        &self,
674        attr: &ast::Meta,
675    ) -> Option<Vec<Option<Either<MacroCallId, BuiltinDeriveImplId>>>> {
676        let adt = attr.parent_attr()?.syntax().parent().and_then(ast::Adt::cast)?;
677        let file_id = self.find_file(adt.syntax()).file_id;
678        let adt = InFile::new(file_id, &adt);
679        let src = InFile::new(file_id, attr.clone());
680        self.with_ctx(|ctx| {
681            let (.., res) = ctx.attr_to_derive_macro_call(adt, src)?;
682            Some(res.to_vec())
683        })
684    }
685
686    pub fn is_derive_annotated(&self, adt: InFile<&ast::Adt>) -> bool {
687        self.with_ctx(|ctx| ctx.file_of_adt_has_derives(adt))
688    }
689
690    pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> {
691        let sa = self.analyze_no_infer(adt.syntax())?;
692        let id = sa.file_id.ast_id_map(self.db).ast_id(adt);
693        let result = sa
694            .resolver
695            .def_map()
696            .derive_helpers_in_scope(InFile::new(sa.file_id, id))?
697            .iter()
698            .map(|(name, macro_, _)| {
699                let macro_name = Macro::from(*macro_).name(self.db).symbol().clone();
700                (name.symbol().clone(), macro_name)
701            })
702            .collect();
703        Some(result)
704    }
705
706    pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroCallId)>> {
707        let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
708            ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
709            ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
710            ast::Item::Union(it) => Some(ast::Adt::Union(it)),
711            _ => None,
712        })?;
713        let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
714        let sa = self.analyze_no_infer(adt.syntax())?;
715        let id = sa.file_id.ast_id_map(self.db).ast_id(&adt);
716        let res: Vec<_> = sa
717            .resolver
718            .def_map()
719            .derive_helpers_in_scope(InFile::new(sa.file_id, id))?
720            .iter()
721            .filter(|&(name, _, _)| *name == attr_name)
722            .filter_map(|&(_, macro_, call)| Some((macro_.into(), call.left()?)))
723            .collect();
724        // FIXME: We filter our builtin derive "fake" expansions, is this correct? Should we still expose them somehow?
725        res.is_empty().not().then_some(res)
726    }
727
728    pub fn is_attr_macro_call(&self, item: InFile<&ast::Item>) -> bool {
729        self.with_ctx(|ctx| ctx.item_to_macro_call(item).is_some())
730    }
731
732    /// Expand the macro call with a different token tree, mapping the `token_to_map` down into the
733    /// expansion. `token_to_map` should be a token from the `speculative args` node.
734    pub fn speculative_expand_macro_call(
735        &self,
736        actual_macro_call: &ast::MacroCall,
737        speculative_args: &ast::TokenTree,
738        token_to_map: SyntaxToken,
739    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
740        let macro_file = self.to_def(actual_macro_call)?;
741        self.speculative_expand_raw(macro_file, speculative_args.syntax(), token_to_map)
742    }
743
744    pub fn speculative_expand_raw(
745        &self,
746        macro_file: MacroCallId,
747        speculative_args: &SyntaxNode,
748        token_to_map: SyntaxToken,
749    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
750        macro_file.expand_speculative(self.db, speculative_args, token_to_map)
751    }
752
753    /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the
754    /// expansion. `token_to_map` should be a token from the `speculative args` node.
755    pub fn speculative_expand_attr_macro(
756        &self,
757        actual_macro_call: &ast::Item,
758        speculative_args: &ast::Item,
759        token_to_map: SyntaxToken,
760    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
761        let macro_call = self.wrap_node_infile(actual_macro_call.clone());
762        let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?;
763        self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map)
764    }
765
766    pub fn speculative_expand_derive_as_pseudo_attr_macro(
767        &self,
768        actual_macro_call: &ast::Attr,
769        speculative_args: &ast::Attr,
770        token_to_map: SyntaxToken,
771    ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
772        let attr = self.wrap_node_infile(actual_macro_call.clone());
773        let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
774        let macro_call_id = self.with_ctx(|ctx| {
775            ctx.attr_to_derive_macro_call(
776                attr.with_value(&adt),
777                attr.with_value(attr.value.meta()?),
778            )
779            .map(|(_, it, _)| it)
780        })?;
781        self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map)
782    }
783
784    /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
785    /// and returns the conflicting locals.
786    pub fn rename_conflicts<'a>(
787        &self,
788        to_be_renamed: &Local<'a>,
789        new_name: &Name,
790    ) -> Vec<Local<'a>> {
791        let (store, root_expr) = to_be_renamed.parent_infer.store_and_root_expr(self.db);
792        let resolver = to_be_renamed.parent.resolver(self.db);
793        let starting_expr = store.binding_owner(to_be_renamed.binding_id).unwrap_or(root_expr);
794        let mut visitor = RenameConflictsVisitor {
795            body: store,
796            conflicts: FxHashSet::default(),
797            db: self.db,
798            new_name: new_name.symbol().clone(),
799            old_name: to_be_renamed.name(self.db).symbol().clone(),
800            owner: to_be_renamed.parent,
801            to_be_renamed: to_be_renamed.binding_id,
802            resolver,
803        };
804        visitor.rename_conflicts(starting_expr);
805        visitor
806            .conflicts
807            .into_iter()
808            .map(|binding_id| Local {
809                parent: to_be_renamed.parent,
810                parent_infer: to_be_renamed.parent_infer,
811                binding_id,
812            })
813            .collect()
814    }
815
816    /// Retrieves all the formatting parts of the format_args! (or `asm!`) template string.
817    pub fn as_format_args_parts(
818        &self,
819        string: &ast::String,
820    ) -> Option<Vec<(TextRange, Option<Either<PathResolution<'db>, InlineAsmOperand>>)>> {
821        let string_start = string.syntax().text_range().start();
822        let token = self.wrap_token_infile(string.syntax().clone());
823        self.descend_into_macros_breakable(token, |token, _| {
824            (|| {
825                let token = token.value;
826                let string = ast::String::cast(token)?;
827                let literal =
828                    string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
829                let parent = literal.parent()?;
830                if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) {
831                    let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
832                    let format_args = self.wrap_node_infile(format_args);
833                    let res = source_analyzer
834                        .as_format_args_parts(self.db, format_args.as_ref())?
835                        .map(|(range, res)| (range + string_start, res.map(Either::Left)))
836                        .collect();
837                    Some(res)
838                } else {
839                    let asm = ast::AsmExpr::cast(parent)?;
840                    let source_analyzer = self.analyze_no_infer(asm.syntax())?;
841                    let line = asm.template().position(|it| *it.syntax() == literal)?;
842                    let asm = self.wrap_node_infile(asm);
843                    let (owner, (expr, asm_parts)) = source_analyzer.as_asm_parts(asm.as_ref())?;
844                    let res = asm_parts
845                        .get(line)?
846                        .iter()
847                        .map(|&(range, index)| {
848                            (
849                                range + string_start,
850                                Some(Either::Right(InlineAsmOperand { owner, expr, index })),
851                            )
852                        })
853                        .collect();
854                    Some(res)
855                }
856            })()
857            .map_or(ControlFlow::Continue(()), ControlFlow::Break)
858        })
859    }
860
861    /// Retrieves the formatting part of the format_args! template string at the given offset.
862    ///
863    // FIXME: Type the return type
864    /// Returns the range (pre-expansion) in the string literal corresponding to the resolution,
865    /// absolute file range (post-expansion)
866    /// of the part in the format string (post-expansion), the corresponding string token and the resolution if it
867    /// exists.
868    // FIXME: Remove this in favor of `check_for_format_args_template_with_file`
869    pub fn check_for_format_args_template(
870        &self,
871        original_token: SyntaxToken,
872        offset: TextSize,
873    ) -> Option<(
874        TextRange,
875        HirFileRange,
876        ast::String,
877        Option<Either<PathResolution<'db>, InlineAsmOperand>>,
878    )> {
879        let original_token =
880            self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?;
881        self.check_for_format_args_template_with_file(original_token, offset)
882    }
883
884    /// Retrieves the formatting part of the format_args! template string at the given offset.
885    ///
886    // FIXME: Type the return type
887    /// Returns the range (pre-expansion) in the string literal corresponding to the resolution,
888    /// absolute file range (post-expansion)
889    /// of the part in the format string, the corresponding string token and the resolution if it
890    /// exists.
891    pub fn check_for_format_args_template_with_file(
892        &self,
893        original_token: InFile<ast::String>,
894        offset: TextSize,
895    ) -> Option<(
896        TextRange,
897        HirFileRange,
898        ast::String,
899        Option<Either<PathResolution<'db>, InlineAsmOperand>>,
900    )> {
901        let relative_offset =
902            offset.checked_sub(original_token.value.syntax().text_range().start())?;
903        self.descend_into_macros_breakable(
904            original_token.as_ref().map(|it| it.syntax().clone()),
905            |token, _| {
906                (|| {
907                    let token = token.map(ast::String::cast).transpose()?;
908                    self.resolve_offset_in_format_args(token.as_ref(), relative_offset).map(
909                        |(range, res)| {
910                            (
911                                range + original_token.value.syntax().text_range().start(),
912                                HirFileRange {
913                                    file_id: token.file_id,
914                                    range: range + token.value.syntax().text_range().start(),
915                                },
916                                token.value,
917                                res,
918                            )
919                        },
920                    )
921                })()
922                .map_or(ControlFlow::Continue(()), ControlFlow::Break)
923            },
924        )
925    }
926
927    fn resolve_offset_in_format_args(
928        &self,
929        InFile { value: string, file_id }: InFile<&ast::String>,
930        offset: TextSize,
931    ) -> Option<(TextRange, Option<Either<PathResolution<'db>, InlineAsmOperand>>)> {
932        debug_assert!(offset <= string.syntax().text_range().len());
933        let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
934        let parent = literal.parent()?;
935        if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) {
936            let source_analyzer =
937                self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?;
938            source_analyzer
939                .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset)
940                .map(|(range, res)| (range, res.map(Either::Left)))
941        } else {
942            let asm = ast::AsmExpr::cast(parent)?;
943            let source_analyzer =
944                self.analyze_impl(InFile::new(file_id, asm.syntax()), None, false)?;
945            let line = asm.template().position(|it| *it.syntax() == literal)?;
946            source_analyzer
947                .resolve_offset_in_asm_template(InFile::new(file_id, &asm), line, offset)
948                .map(|(owner, (expr, range, index))| {
949                    (range, Some(Either::Right(InlineAsmOperand { owner, expr, index })))
950                })
951        }
952    }
953
954    pub fn debug_hir_at(&self, token: SyntaxToken) -> Option<String> {
955        self.analyze_no_infer(&token.parent()?).and_then(|it| {
956            Some(match it.body_or_sig.as_ref()? {
957                crate::source_analyzer::BodyOrSig::Body { def, body, .. } => {
958                    hir_def::expr_store::pretty::print_body_hir(
959                        self.db,
960                        body,
961                        *def,
962                        it.file_id.edition(self.db),
963                    )
964                }
965                &crate::source_analyzer::BodyOrSig::VariantFields { def, .. } => {
966                    hir_def::expr_store::pretty::print_variant_body_hir(
967                        self.db,
968                        def,
969                        it.file_id.edition(self.db),
970                    )
971                }
972                &crate::source_analyzer::BodyOrSig::Sig { def, .. } => {
973                    hir_def::expr_store::pretty::print_signature(
974                        self.db,
975                        def,
976                        it.file_id.edition(self.db),
977                    )
978                }
979            })
980        })
981    }
982
983    /// Descends the token into the include expansion, if its file is an included file.
984    pub fn descend_token_into_include_expansion(
985        &self,
986        tok: InRealFile<SyntaxToken>,
987    ) -> InFile<SyntaxToken> {
988        let Some(include) =
989            self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, tok.file_id)
990        else {
991            return tok.into();
992        };
993        let span =
994            HirFileId::from(tok.file_id).span_map(self.db).span_for_range(tok.value.text_range());
995        let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| {
996            Some(
997                ctx.cache
998                    .get_or_insert_expansion(ctx.db, include)
999                    .map_range_down(span)?
1000                    .map(SmallVec::<[_; 2]>::from_iter),
1001            )
1002        }) else {
1003            return tok.into();
1004        };
1005        // We should only get one result at most
1006        mapped_tokens.pop().map_or_else(|| tok.into(), |(tok, _)| InFile::new(file_id.into(), tok))
1007    }
1008
1009    /// Maps a node down by mapping its first and last token down.
1010    pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
1011        // This might not be the correct way to do this, but it works for now
1012        let mut res = smallvec![];
1013        let tokens = (|| {
1014            // FIXME: the trivia skipping should not be necessary
1015            let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?;
1016            let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?;
1017            Some((first, last))
1018        })();
1019        let (first, last) = match tokens {
1020            Some(it) => it,
1021            None => return res,
1022        };
1023        let file = self.find_file(node.syntax());
1024
1025        if first == last {
1026            // node is just the token, so descend the token
1027            self.descend_into_macros_all(
1028                InFile::new(file.file_id, first),
1029                false,
1030                &mut |InFile { value, .. }, _ctx| {
1031                    if let Some(node) = value
1032                        .parent_ancestors()
1033                        .take_while(|it| it.text_range() == value.text_range())
1034                        .find_map(N::cast)
1035                    {
1036                        res.push(node)
1037                    }
1038                },
1039            );
1040        } else {
1041            // Descend first and last token, then zip them to look for the node they belong to
1042            let mut scratch: SmallVec<[_; 1]> = smallvec![];
1043            self.descend_into_macros_all(
1044                InFile::new(file.file_id, first),
1045                false,
1046                &mut |token, _ctx| scratch.push(token),
1047            );
1048
1049            let mut scratch = scratch.into_iter();
1050            self.descend_into_macros_all(
1051                InFile::new(file.file_id, last),
1052                false,
1053                &mut |InFile { value: last, file_id: last_fid }, _ctx| {
1054                    if let Some(InFile { value: first, file_id: first_fid }) = scratch.next()
1055                        && first_fid == last_fid
1056                        && let Some(p) = first.parent()
1057                    {
1058                        let range = first.text_range().cover(last.text_range());
1059                        let node = p
1060                            .tree_top()
1061                            .covering_element(range)
1062                            .ancestors()
1063                            .take_while(|it| it.text_range() == range)
1064                            .find_map(N::cast);
1065                        if let Some(node) = node {
1066                            res.push(node);
1067                        }
1068                    }
1069                },
1070            );
1071        }
1072        res
1073    }
1074
1075    /// Returns true if the given input is within a macro call.
1076    ///
1077    /// Note that if this token itself is within the context of a macro expansion does not matter.
1078    /// That is, we strictly check if it lies inside the input of a macro call.
1079    pub fn is_inside_macro_call(&self, token @ InFile { value, .. }: InFile<&SyntaxToken>) -> bool {
1080        value.parent_ancestors().any(|ancestor| {
1081            if let Some(macro_call) = ast::MacroCall::cast(ancestor.clone())
1082                // If this is the *path* of a macro, it's not inside the call.
1083                && macro_call.path().is_none_or(|path| {
1084                    !path.syntax().text_range().contains_range(value.text_range())
1085                })
1086            {
1087                return true;
1088            }
1089
1090            let Some(item) = ast::Item::cast(ancestor) else {
1091                return false;
1092            };
1093            self.with_ctx(|ctx| {
1094                if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
1095                    return true;
1096                }
1097                let adt = match item {
1098                    ast::Item::Struct(it) => it.into(),
1099                    ast::Item::Enum(it) => it.into(),
1100                    ast::Item::Union(it) => it.into(),
1101                    _ => return false,
1102                };
1103                ctx.file_of_adt_has_derives(token.with_value(&adt))
1104            })
1105        })
1106    }
1107
1108    pub fn descend_into_macros_cb(
1109        &self,
1110        token: SyntaxToken,
1111        mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext),
1112    ) {
1113        self.descend_into_macros_all(self.wrap_token_infile(token), false, &mut |t, ctx| {
1114            cb(t, ctx)
1115        });
1116    }
1117
1118    pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
1119        let mut res = smallvec![];
1120        self.descend_into_macros_all(
1121            self.wrap_token_infile(token.clone()),
1122            false,
1123            &mut |t, _ctx| res.push(t.value),
1124        );
1125        if res.is_empty() {
1126            res.push(token);
1127        }
1128        res
1129    }
1130
1131    pub fn descend_into_macros_no_opaque(
1132        &self,
1133        token: SyntaxToken,
1134        always_descend_into_derives: bool,
1135    ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
1136        let mut res = smallvec![];
1137        let token = self.wrap_token_infile(token);
1138        self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| {
1139            if !ctx.is_opaque(self.db) {
1140                // Don't descend into opaque contexts
1141                res.push(t);
1142            }
1143        });
1144        if res.is_empty() {
1145            res.push(token);
1146        }
1147        res
1148    }
1149
1150    pub fn descend_into_macros_breakable<T>(
1151        &self,
1152        token: InFile<SyntaxToken>,
1153        mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
1154    ) -> Option<T> {
1155        self.descend_into_macros_impl(token, false, &mut cb)
1156    }
1157
1158    /// Descends the token into expansions, returning the tokens that matches the input
1159    /// token's [`SyntaxKind`] and text.
1160    pub fn descend_into_macros_exact(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
1161        let mut r = smallvec![];
1162        let text = token.text();
1163        let kind = token.kind();
1164
1165        self.descend_into_macros_cb(token.clone(), |InFile { value, file_id: _ }, ctx| {
1166            let mapped_kind = value.kind();
1167            let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
1168            let matches = (kind == mapped_kind || any_ident_match())
1169                && text == value.text()
1170                && !ctx.is_opaque(self.db);
1171            if matches {
1172                r.push(value);
1173            }
1174        });
1175        if r.is_empty() {
1176            r.push(token);
1177        }
1178        r
1179    }
1180
1181    /// Descends the token into expansions, returning the tokens that matches the input
1182    /// token's [`SyntaxKind`] and text.
1183    pub fn descend_into_macros_exact_with_file(
1184        &self,
1185        token: SyntaxToken,
1186    ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
1187        let mut r = smallvec![];
1188        let text = token.text();
1189        let kind = token.kind();
1190
1191        self.descend_into_macros_cb(token.clone(), |InFile { value, file_id }, ctx| {
1192            let mapped_kind = value.kind();
1193            let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
1194            let matches = (kind == mapped_kind || any_ident_match())
1195                && text == value.text()
1196                && !ctx.is_opaque(self.db);
1197            if matches {
1198                r.push(InFile { value, file_id });
1199            }
1200        });
1201        if r.is_empty() {
1202            r.push(self.wrap_token_infile(token));
1203        }
1204        r
1205    }
1206
1207    /// Descends the token into expansions, returning the first token that matches the input
1208    /// token's [`SyntaxKind`] and text.
1209    pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken {
1210        let text = token.text();
1211        let kind = token.kind();
1212        self.descend_into_macros_breakable(
1213            self.wrap_token_infile(token.clone()),
1214            |InFile { value, file_id: _ }, _ctx| {
1215                let mapped_kind = value.kind();
1216                let any_ident_match =
1217                    || kind.is_any_identifier() && value.kind().is_any_identifier();
1218                let matches = (kind == mapped_kind || any_ident_match()) && text == value.text();
1219                if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) }
1220            },
1221        )
1222        .unwrap_or(token)
1223    }
1224
1225    fn descend_into_macros_all(
1226        &self,
1227        token: InFile<SyntaxToken>,
1228        always_descend_into_derives: bool,
1229        f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext),
1230    ) {
1231        self.descend_into_macros_impl(token, always_descend_into_derives, &mut |tok, ctx| {
1232            f(tok, ctx);
1233            CONTINUE_NO_BREAKS
1234        });
1235    }
1236
1237    fn descend_into_macros_impl<T>(
1238        &self,
1239        InFile { value: token, file_id }: InFile<SyntaxToken>,
1240        always_descend_into_derives: bool,
1241        f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
1242    ) -> Option<T> {
1243        let _p = tracing::info_span!("descend_into_macros_impl").entered();
1244
1245        let db = self.db;
1246        let span = file_id.span_map(db).span_for_range(token.text_range());
1247
1248        // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
1249        let process_expansion_for_token =
1250            |ctx: &mut SourceToDefCtx<'_, '_>, stack: &mut Vec<_>, macro_file| {
1251                let InMacroFile { file_id, value: mapped_tokens } = ctx
1252                    .cache
1253                    .get_or_insert_expansion(ctx.db, macro_file)
1254                    .map_range_down(span)?
1255                    .map(SmallVec::<[_; 2]>::from_iter);
1256                // we have found a mapping for the token if the vec is non-empty
1257                let res = mapped_tokens.is_empty().not().then_some(());
1258                // requeue the tokens we got from mapping our current token down
1259                stack.push((HirFileId::from(file_id), mapped_tokens));
1260                res
1261            };
1262
1263        // A stack of tokens to process, along with the file they came from
1264        // These are tracked to know which macro calls we still have to look into
1265        // the tokens themselves aren't that interesting as the span that is being used to map
1266        // things down never changes.
1267        let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
1268        let include = file_id
1269            .file_id()
1270            .and_then(|file_id| self.s2d_cache.borrow_mut().get_or_insert_include_for(db, file_id));
1271        match include {
1272            Some(include) => {
1273                // include! inputs are always from real files, so they only need to be handled once upfront
1274                self.with_ctx(|ctx| process_expansion_for_token(ctx, &mut stack, include))?;
1275            }
1276            None => {
1277                stack.push((file_id, smallvec![(token, span.ctx)]));
1278            }
1279        }
1280
1281        let mut m_cache = self.macro_call_cache.borrow_mut();
1282
1283        // Filters out all tokens that contain the given range (usually the macro call), any such
1284        // token is redundant as the corresponding macro call has already been processed
1285        let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
1286            tokens.retain(|(t, _): &mut (SyntaxToken, _)| !range.contains_range(t.text_range()))
1287        };
1288
1289        while let Some((expansion, ref mut tokens)) = stack.pop() {
1290            // Reverse the tokens so we prefer first tokens (to accommodate for popping from the
1291            // back)
1292            // alternatively we could pop from the front but that would shift the content on every pop
1293            tokens.reverse();
1294            while let Some((token, ctx)) = tokens.pop() {
1295                let was_not_remapped = (|| {
1296                    // First expand into attribute invocations, this is required to be handled
1297                    // upfront as any other macro call within will not semantically resolve unless
1298                    // also descended.
1299                    let res = self.with_ctx(|ctx| {
1300                        token
1301                            .parent_ancestors()
1302                            .filter_map(ast::Item::cast)
1303                            // FIXME: This might work incorrectly when we have a derive, followed by
1304                            // an attribute on an item, like:
1305                            // ```
1306                            // #[derive(Debug$0)]
1307                            // #[my_attr]
1308                            // struct MyStruct;
1309                            // ```
1310                            // here we should not consider the attribute at all, as our cursor
1311                            // technically lies outside of its expansion
1312                            .find_map(|item| {
1313                                // Don't force populate the dyn cache for items that don't have an attribute anyways
1314                                item.attrs().next()?;
1315                                ctx.item_to_macro_call(InFile::new(expansion, &item))
1316                                    .zip(Some(item))
1317                            })
1318                            .map(|(call_id, item)| {
1319                                let item_range = item.syntax().text_range();
1320                                let loc = call_id.loc(db);
1321                                let text_range = match &loc.kind {
1322                                    hir_expand::MacroCallKind::Attr {
1323                                        censored_attr_ids: attr_ids,
1324                                        ..
1325                                    } => {
1326                                        // FIXME: here, the attribute's text range is used to strip away all
1327                                        // entries from the start of the attribute "list" up the invoking
1328                                        // attribute. But in
1329                                        // ```
1330                                        // mod foo {
1331                                        //     #![inner]
1332                                        // }
1333                                        // ```
1334                                        // we don't wanna strip away stuff in the `mod foo {` range, that is
1335                                        // here if the id corresponds to an inner attribute we got strip all
1336                                        // text ranges of the outer ones, and then all of the inner ones up
1337                                        // to the invoking attribute so that the inbetween is ignored.
1338                                        // FIXME: Should cfg_attr be handled differently?
1339                                        let (attr, _) = attr_ids
1340                                            .invoc_attr()
1341                                            .find_attr_range_with_source(db, loc.krate, &item);
1342                                        let start = attr.syntax().text_range().start();
1343                                        TextRange::new(start, item_range.end())
1344                                    }
1345                                    _ => item_range,
1346                                };
1347                                filter_duplicates(tokens, text_range);
1348                                process_expansion_for_token(ctx, &mut stack, call_id)
1349                            })
1350                    });
1351
1352                    if let Some(res) = res {
1353                        return res;
1354                    }
1355
1356                    if always_descend_into_derives {
1357                        let res = self.with_ctx(|ctx| {
1358                            let (derives, adt) = token
1359                                .parent_ancestors()
1360                                .filter_map(ast::Adt::cast)
1361                                .find_map(|adt| {
1362                                    Some((
1363                                        ctx.derive_macro_calls(InFile::new(expansion, &adt))?
1364                                            .map(|(a, b, c)| (a, b, c.to_owned()))
1365                                            .collect::<SmallVec<[_; 2]>>(),
1366                                        adt,
1367                                    ))
1368                                })?;
1369                            for (_, derive_attr, derives) in derives {
1370                                // as there may be multiple derives registering the same helper
1371                                // name, we gotta make sure to call this for all of them!
1372                                // FIXME: We need to call `f` for all of them as well though!
1373                                process_expansion_for_token(ctx, &mut stack, derive_attr);
1374                                for derive in derives.into_iter().flatten() {
1375                                    let Either::Left(derive) = derive else { continue };
1376                                    process_expansion_for_token(ctx, &mut stack, derive);
1377                                }
1378                            }
1379                            // remove all tokens that are within the derives expansion
1380                            filter_duplicates(tokens, adt.syntax().text_range());
1381                            Some(())
1382                        });
1383                        // if we found derives, we can early exit. There is no way we can be in any
1384                        // macro call at this point given we are not in a token tree
1385                        if let Some(()) = res {
1386                            // Note: derives do not remap the original token. Furthermore, we want
1387                            // the original token to be before the derives in the list, because if they
1388                            // upmap to the same token and we deduplicate them (e.g. in rename), we
1389                            // want the original token to remain, not the derive.
1390                            return None;
1391                        }
1392                    }
1393                    // Then check for token trees, that means we are either in a function-like macro or
1394                    // secondary attribute inputs
1395                    let tt = token
1396                        .parent_ancestors()
1397                        .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
1398                        .last()?;
1399
1400                    match tt {
1401                        // function-like macro call
1402                        Either::Left(tt) => {
1403                            let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
1404                            if tt.left_delimiter_token().map_or(false, |it| it == token) {
1405                                return None;
1406                            }
1407                            if tt.right_delimiter_token().map_or(false, |it| it == token) {
1408                                return None;
1409                            }
1410                            let mcall = InFile::new(expansion, macro_call);
1411                            let file_id = match m_cache.get(&mcall) {
1412                                Some(&it) => it,
1413                                None => {
1414                                    let it = ast::MacroCall::to_def(self, mcall.as_ref())?;
1415                                    m_cache.insert(mcall, it);
1416                                    it
1417                                }
1418                            };
1419                            let text_range = tt.syntax().text_range();
1420                            filter_duplicates(tokens, text_range);
1421
1422                            self.with_ctx(|ctx| {
1423                                process_expansion_for_token(ctx, &mut stack, file_id).or(file_id
1424                                    .eager_arg(db)
1425                                    .and_then(|arg| {
1426                                        // also descend into eager expansions
1427                                        process_expansion_for_token(ctx, &mut stack, arg)
1428                                    }))
1429                            })
1430                        }
1431                        Either::Right(_) if always_descend_into_derives => None,
1432                        // derive or derive helper
1433                        Either::Right(meta) => {
1434                            // attribute we failed expansion for earlier, this might be a derive invocation
1435                            // or derive helper attribute
1436                            let attr = meta.parent_attr()?;
1437                            let adt = match attr.syntax().parent().and_then(ast::Adt::cast) {
1438                                Some(adt) => {
1439                                    // this might be a derive on an ADT
1440                                    let res = self.with_ctx(|ctx| {
1441                                        // so try downmapping the token into the pseudo derive expansion
1442                                        // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
1443                                        let derive_call = ctx
1444                                            .attr_to_derive_macro_call(
1445                                                InFile::new(expansion, &adt),
1446                                                InFile::new(expansion, meta.clone()),
1447                                            )?
1448                                            .1;
1449
1450                                        // resolved to a derive
1451                                        let text_range = attr.syntax().text_range();
1452                                        // remove any other token in this macro input, all their mappings are the
1453                                        // same as this
1454                                        tokens.retain(|(t, _)| {
1455                                            !text_range.contains_range(t.text_range())
1456                                        });
1457                                        Some(process_expansion_for_token(
1458                                            ctx,
1459                                            &mut stack,
1460                                            derive_call,
1461                                        ))
1462                                    });
1463                                    if let Some(res) = res {
1464                                        return res;
1465                                    }
1466                                    Some(adt)
1467                                }
1468                                None => {
1469                                    // Otherwise this could be a derive helper on a variant or field
1470                                    attr.syntax().ancestors().find_map(ast::Item::cast).and_then(
1471                                        |it| match it {
1472                                            ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
1473                                            ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
1474                                            ast::Item::Union(it) => Some(ast::Adt::Union(it)),
1475                                            _ => None,
1476                                        },
1477                                    )
1478                                }
1479                            }?;
1480                            let attr_name =
1481                                attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
1482                            // Not an attribute, nor a derive, so it's either an inert attribute or a derive helper
1483                            // Try to resolve to a derive helper and downmap
1484                            let resolver = &token
1485                                .parent()
1486                                .and_then(|parent| {
1487                                    self.analyze_impl(InFile::new(expansion, &parent), None, false)
1488                                })?
1489                                .resolver;
1490                            let id = expansion.ast_id_map(db).ast_id(&adt);
1491                            let helpers = resolver
1492                                .def_map()
1493                                .derive_helpers_in_scope(InFile::new(expansion, id))?;
1494
1495                            if !helpers.is_empty() {
1496                                let text_range = attr.syntax().text_range();
1497                                filter_duplicates(tokens, text_range);
1498                            }
1499
1500                            let mut res = None;
1501                            self.with_ctx(|ctx| {
1502                                for (.., derive) in
1503                                    helpers.iter().filter(|(helper, ..)| *helper == attr_name)
1504                                {
1505                                    let Either::Left(derive) = *derive else { continue };
1506                                    // as there may be multiple derives registering the same helper
1507                                    // name, we gotta make sure to call this for all of them!
1508                                    // FIXME: We need to call `f` for all of them as well though!
1509                                    res = res
1510                                        .or(process_expansion_for_token(ctx, &mut stack, derive));
1511                                }
1512                                res
1513                            })
1514                        }
1515                    }
1516                })()
1517                .is_none();
1518                if was_not_remapped
1519                    && let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx)
1520                {
1521                    return Some(b);
1522                }
1523            }
1524        }
1525        None
1526    }
1527
1528    // Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
1529    // traversing the inner iterator when it finds a node.
1530    // The outer iterator is over the tokens descendants
1531    // The inner iterator is the ancestors of a descendant
1532    fn descend_node_at_offset(
1533        &self,
1534        node: &SyntaxNode,
1535        offset: TextSize,
1536    ) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ {
1537        node.token_at_offset(offset)
1538            .map(move |token| self.descend_into_macros_exact(token))
1539            .map(|descendants| {
1540                descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it))
1541            })
1542            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
1543            // See algo::ancestors_at_offset, which uses the same approach
1544            .kmerge_by(|left, right| {
1545                left.clone()
1546                    .map(|node| node.text_range().len())
1547                    .lt(right.clone().map(|node| node.text_range().len()))
1548            })
1549    }
1550
1551    /// Attempts to map the node out of macro expanded files returning the original file range.
1552    /// If upmapping is not possible, this will fall back to the range of the macro call of the
1553    /// macro file the node resides in.
1554    pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
1555        let node = self.find_file(node);
1556        node.original_file_range_rooted(self.db)
1557    }
1558
1559    /// Attempts to map the node out of macro expanded files returning the original file range.
1560    pub fn original_range_opt(&self, node: &SyntaxNode) -> Option<FileRange> {
1561        let node = self.find_file(node);
1562        node.original_file_range_opt(self.db).filter(|(_, ctx)| ctx.is_root()).map(TupleExt::head)
1563    }
1564
1565    /// Attempts to map the node out of macro expanded files.
1566    /// This only works for attribute expansions, as other ones do not have nodes as input.
1567    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
1568        self.wrap_node_infile(node).original_ast_node_rooted(self.db).map(
1569            |InRealFile { file_id, value }| {
1570                self.cache(value.syntax().tree_top(), file_id.into());
1571                value
1572            },
1573        )
1574    }
1575
1576    /// Attempts to map the node out of macro expanded files.
1577    /// This only works for attribute expansions, as other ones do not have nodes as input.
1578    pub fn original_syntax_node_rooted(&self, node: &SyntaxNode) -> Option<SyntaxNode> {
1579        let InFile { file_id, .. } = self.find_file(node);
1580        InFile::new(file_id, node).original_syntax_node_rooted(self.db).map(
1581            |InRealFile { file_id, value }| {
1582                self.cache(value.tree_top(), file_id.into());
1583                value
1584            },
1585        )
1586    }
1587
1588    pub fn diagnostics_display_range(
1589        &self,
1590        src: InFile<SyntaxNodePtr>,
1591    ) -> FileRangeWrapper<FileId> {
1592        let root = self.parse_or_expand(src.file_id);
1593        let node = src.map(|it| it.to_node(&root));
1594        let FileRange { file_id, range } = node.as_ref().original_file_range_rooted(self.db);
1595        FileRangeWrapper { file_id: file_id.file_id(self.db), range }
1596    }
1597
1598    pub fn diagnostics_display_range_for_range(
1599        &self,
1600        src: InFile<TextRange>,
1601    ) -> FileRangeWrapper<FileId> {
1602        let FileRange { file_id, range } = src.original_node_file_range_rooted(self.db);
1603        FileRangeWrapper { file_id: file_id.file_id(self.db), range }
1604    }
1605
1606    fn token_ancestors_with_macros(
1607        &self,
1608        token: SyntaxToken,
1609    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
1610        token.parent().into_iter().flat_map(move |parent| self.ancestors_with_macros(parent))
1611    }
1612
1613    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
1614    // FIXME: Replace with `ancestors_with_macros_file` when all usages are updated.
1615    pub fn ancestors_with_macros(
1616        &self,
1617        node: SyntaxNode,
1618    ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
1619        let node = self.find_file(&node);
1620        self.ancestors_with_macros_file(node.cloned()).map(|it| it.value)
1621    }
1622
1623    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
1624    pub fn ancestors_with_macros_file(
1625        &self,
1626        node: InFile<SyntaxNode>,
1627    ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
1628        iter::successors(Some(node), move |&InFile { file_id, ref value }| match value.parent() {
1629            Some(parent) => Some(InFile::new(file_id, parent)),
1630            None => {
1631                let macro_file = file_id.macro_file()?;
1632
1633                self.with_ctx(|ctx| {
1634                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
1635                    expansion_info.arg().map(|node| node?.parent()).transpose()
1636                })
1637                .inspect(|node| {
1638                    self.cache(node.value.tree_top(), node.file_id);
1639                })
1640            }
1641        })
1642    }
1643
1644    pub fn ancestors_at_offset_with_macros(
1645        &self,
1646        node: &SyntaxNode,
1647        offset: TextSize,
1648    ) -> impl Iterator<Item = SyntaxNode> + '_ {
1649        node.token_at_offset(offset)
1650            .map(|token| self.token_ancestors_with_macros(token))
1651            .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
1652    }
1653
1654    /// Returns the `return` expressions in this function's body,
1655    /// excluding those inside closures or async blocks.
1656    pub fn fn_return_points(&self, func: Function) -> Vec<InFile<ast::ReturnExpr>> {
1657        let func_id = match func.id {
1658            AnyFunctionId::FunctionId(id) => id,
1659            _ => return vec![],
1660        };
1661        let (body, source_map) = Body::with_source_map(self.db, func_id.into());
1662
1663        fn collect_returns(
1664            sema: &SemanticsImpl<'_>,
1665            body: &Body,
1666            source_map: &hir_def::expr_store::ExpressionStoreSourceMap,
1667            expr_id: ExprId,
1668            acc: &mut Vec<InFile<ast::ReturnExpr>>,
1669        ) {
1670            match &body[expr_id] {
1671                Expr::Closure { .. } | Expr::Const(_) => return,
1672                Expr::Return { .. } => {
1673                    if let Ok(source) = source_map.expr_syntax(expr_id)
1674                        && let Some(ret_expr) = source.value.cast::<ast::ReturnExpr>()
1675                    {
1676                        let root = sema.parse_or_expand(source.file_id);
1677                        acc.push(InFile::new(source.file_id, ret_expr.to_node(&root)));
1678                    }
1679                }
1680                _ => {}
1681            }
1682            body.walk_child_exprs(expr_id, |child| {
1683                collect_returns(sema, body, source_map, child, acc);
1684            });
1685        }
1686
1687        let mut returns = vec![];
1688        collect_returns(self, body, source_map, body.root_expr(), &mut returns);
1689        returns
1690    }
1691
1692    pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
1693        let text = lifetime.text();
1694        let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {
1695            let gpl = ast::AnyHasGenericParams::cast(syn)?.generic_param_list()?;
1696            gpl.lifetime_params()
1697                .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text))
1698        })?;
1699        let src = self.wrap_node_infile(lifetime_param);
1700        ToDef::to_def(self, src.as_ref())
1701    }
1702
1703    pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> {
1704        let src = self.wrap_node_infile(label.clone());
1705        let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?;
1706        Some(Label { parent, label_id })
1707    }
1708
1709    pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type<'db>> {
1710        let analyze = self.analyze(ty.syntax())?;
1711        analyze.type_of_type(self.db, ty)
1712    }
1713
1714    pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
1715        let parent_ty = path.syntax().parent().and_then(ast::Type::cast)?;
1716        let analyze = self.analyze(path.syntax())?;
1717        let ty = analyze.store_sm()?.node_type(InFile::new(analyze.file_id, &parent_ty))?;
1718        let path = match &analyze.store()?.types[ty] {
1719            hir_def::type_ref::TypeRef::Path(path) => path,
1720            _ => return None,
1721        };
1722        match analyze.resolver.resolve_path_in_type_ns_fully(self.db, path)? {
1723            TypeNs::TraitId(trait_id) => Some(trait_id.into()),
1724            _ => None,
1725        }
1726    }
1727
1728    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjustment<'db>>> {
1729        let mutability = |m| match m {
1730            hir_ty::next_solver::Mutability::Not => Mutability::Shared,
1731            hir_ty::next_solver::Mutability::Mut => Mutability::Mut,
1732        };
1733
1734        let analyzer = self.analyze(expr.syntax())?;
1735
1736        let (mut source_ty, _) = analyzer.type_of_expr(self.db, expr)?;
1737
1738        analyzer.expr_adjustments(expr).map(|it| {
1739            it.iter()
1740                .map(|adjust| {
1741                    let target = analyzer.ty(adjust.target.as_ref());
1742                    let kind = match adjust.kind {
1743                        hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
1744                        hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
1745                            // FIXME: Should we handle unknown mutability better?
1746                            Adjust::Deref(Some(OverloadedDeref(mutability(m))))
1747                        }
1748                        hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
1749                        hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
1750                            Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
1751                        }
1752                        hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
1753                            // FIXME: Handle lifetimes here
1754                            Adjust::Borrow(AutoBorrow::Ref(mutability(m.into())))
1755                        }
1756                        hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
1757                    };
1758
1759                    // Update `source_ty` for the next adjustment
1760                    let source = mem::replace(&mut source_ty, target.clone());
1761
1762                    Adjustment { source, target, kind }
1763                })
1764                .collect()
1765        })
1766    }
1767
1768    pub fn expr_is_diverging(&self, expr: &ast::Expr) -> bool {
1769        (|| self.analyze(expr.syntax())?.expr_is_diverging(self.db, expr))().unwrap_or(false)
1770    }
1771
1772    pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo<'db>> {
1773        self.analyze(expr.syntax())?
1774            .type_of_expr(self.db, expr)
1775            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
1776    }
1777
1778    pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo<'db>> {
1779        self.analyze(pat.syntax())?
1780            .type_of_pat(self.db, pat)
1781            .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
1782    }
1783
1784    /// It also includes the changes that binding mode makes in the type. For example in
1785    /// `let ref x @ Some(_) = None` the result of `type_of_pat` is `Option<T>` but the result
1786    /// of this function is `&mut Option<T>`
1787    pub fn type_of_binding_in_pat(&self, pat: &ast::IdentPat) -> Option<Type<'db>> {
1788        self.analyze(pat.syntax())?.type_of_binding_in_pat(self.db, pat)
1789    }
1790
1791    pub fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type<'db>> {
1792        self.analyze(param.syntax())?.type_of_self(self.db, param)
1793    }
1794
1795    pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type<'db>; 1]> {
1796        self.analyze(pat.syntax())
1797            .and_then(|it| it.pattern_adjustments(self.db, pat))
1798            .unwrap_or_default()
1799    }
1800
1801    pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
1802        self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
1803    }
1804
1805    pub fn resolve_expr_as_callable(&self, call: &ast::Expr) -> Option<Callable<'db>> {
1806        self.analyze(call.syntax())?.resolve_expr_as_callable(self.db, call)
1807    }
1808
1809    pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
1810        self.analyze(call.syntax())?.resolve_method_call(self.db, call)
1811    }
1812
1813    /// Attempts to resolve this call expression as a method call falling back to resolving it as a field.
1814    pub fn resolve_method_call_fallback(
1815        &self,
1816        call: &ast::MethodCallExpr,
1817    ) -> Option<(Either<Function, Field>, Option<GenericSubstitution<'db>>)> {
1818        self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
1819    }
1820
1821    /// Env is used to derive the trait environment
1822    // FIXME: better api for the trait environment
1823    pub fn resolve_trait_impl_method(
1824        &self,
1825        env: Type<'db>,
1826        trait_: Trait,
1827        func: Function,
1828        subst: impl IntoIterator<Item = Type<'db>>,
1829    ) -> Option<Function> {
1830        let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) };
1831        let interner = DbInterner::new_no_crate(self.db);
1832        let mut subst = subst.into_iter();
1833        let substs = hir_ty::next_solver::GenericArgs::for_item(
1834            interner,
1835            trait_.id.into(),
1836            |_, id, _, _| {
1837                assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type");
1838                subst.next().expect("too few subst").ty.skip_binder().into()
1839            },
1840        );
1841        assert!(subst.next().is_none(), "too many subst");
1842        Some(match self.db.lookup_impl_method(env.param_env(self.db), func, substs).0 {
1843            Either::Left(it) => it.into(),
1844            Either::Right((impl_, method)) => {
1845                Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }
1846            }
1847        })
1848    }
1849
1850    fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
1851        self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
1852    }
1853
1854    fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
1855        self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
1856    }
1857
1858    fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
1859        self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
1860    }
1861
1862    fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
1863        self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
1864    }
1865
1866    fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
1867        self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
1868    }
1869
1870    fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
1871        self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
1872    }
1873
1874    fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
1875        self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
1876    }
1877
1878    /// The type that the associated `try` block, closure or function expects.
1879    pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option<Type<'db>> {
1880        self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| {
1881            if let Some(try_block) = ast::BlockExpr::cast(parent.clone())
1882                && try_block.try_block_modifier().is_some()
1883            {
1884                Some(self.type_of_expr(&try_block.into())?.original)
1885            } else if let Some(closure) = ast::ClosureExpr::cast(parent.clone()) {
1886                Some(
1887                    self.type_of_expr(&closure.into())?
1888                        .original
1889                        .as_callable(self.db)?
1890                        .return_type(),
1891                )
1892            } else if let Some(function) = ast::Fn::cast(parent) {
1893                Some(self.to_def(&function)?.ret_type(self.db))
1894            } else {
1895                None
1896            }
1897        })
1898    }
1899
1900    // This does not resolve the method call to the correct trait impl!
1901    // We should probably fix that.
1902    pub fn resolve_method_call_as_callable(
1903        &self,
1904        call: &ast::MethodCallExpr,
1905    ) -> Option<Callable<'db>> {
1906        self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
1907    }
1908
1909    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Either<Field, TupleField<'db>>> {
1910        self.analyze(field.syntax())?.resolve_field(field)
1911    }
1912
1913    pub fn resolve_field_fallback(
1914        &self,
1915        field: &ast::FieldExpr,
1916    ) -> Option<(Either<Either<Field, TupleField<'db>>, Function>, Option<GenericSubstitution<'db>>)>
1917    {
1918        self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
1919    }
1920
1921    pub fn resolve_record_field(
1922        &self,
1923        field: &ast::RecordExprField,
1924    ) -> Option<(Field, Option<Local<'db>>, Type<'db>)> {
1925        self.resolve_record_field_with_substitution(field)
1926            .map(|(field, local, ty, _)| (field, local, ty))
1927    }
1928
1929    pub fn resolve_record_field_with_substitution(
1930        &self,
1931        field: &ast::RecordExprField,
1932    ) -> Option<(Field, Option<Local<'db>>, Type<'db>, GenericSubstitution<'db>)> {
1933        self.analyze(field.syntax())?.resolve_record_field(self.db, field)
1934    }
1935
1936    pub fn resolve_record_pat_field(
1937        &self,
1938        field: &ast::RecordPatField,
1939    ) -> Option<(Field, Type<'db>)> {
1940        self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
1941    }
1942
1943    pub fn resolve_record_pat_field_with_subst(
1944        &self,
1945        field: &ast::RecordPatField,
1946    ) -> Option<(Field, Type<'db>, GenericSubstitution<'db>)> {
1947        self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
1948    }
1949
1950    // FIXME: Remove this from https://github.com/rust-lang/rust-analyzer/pull/22449#discussion_r3299763452
1951    pub fn resolve_tuple_struct_pat_fields(
1952        &self,
1953        tuple_struct_pat: &ast::TupleStructPat,
1954    ) -> Option<Vec<(Field, Type<'db>)>> {
1955        self.analyze(tuple_struct_pat.syntax())?
1956            .resolve_tuple_struct_pat_fields(self.db, tuple_struct_pat)
1957    }
1958
1959    // FIXME: Replace this with `resolve_macro_call2`
1960    pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
1961        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
1962        self.resolve_macro_call2(macro_call)
1963    }
1964
1965    pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option<Macro> {
1966        self.to_def2(macro_call)
1967            .and_then(|call| self.with_ctx(|ctx| macro_call_to_macro_id(ctx, call)))
1968            .map(Into::into)
1969    }
1970
1971    pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool {
1972        self.resolve_macro_call2(macro_call)
1973            .is_some_and(|m| matches!(m.id, MacroId::ProcMacroId(..)))
1974    }
1975
1976    pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
1977        self.to_def(macro_call)?.expansion_span_map(self.db).matched_arm
1978    }
1979
1980    pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> {
1981        let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() };
1982        let (body, source_map) = ExpressionStore::with_source_map(self.db, def);
1983        let mut res = FxHashSet::default();
1984        self.with_all_infers_for_store(def, &mut |infer| {
1985            for root in body.expr_roots() {
1986                unsafe_operations(self.db, infer, def, body, root, &mut |node, _| {
1987                    if let Ok(node) = source_map.expr_or_pat_syntax(node) {
1988                        res.insert(node);
1989                    }
1990                });
1991            }
1992        });
1993        res
1994    }
1995
1996    pub fn get_unsafe_ops_for_unsafe_block(&self, block: ast::BlockExpr) -> Vec<ExprOrPatSource> {
1997        always!(block.unsafe_token().is_some());
1998        let Some(sa) = self.analyze(block.syntax()) else { return vec![] };
1999        let Some((def, store, sm, Some(infer))) = sa.def() else { return vec![] };
2000        let block = self.wrap_node_infile(ast::Expr::from(block));
2001        let Some(ExprOrPatId::ExprId(block)) = sm.node_expr(block.as_ref()) else {
2002            return Vec::new();
2003        };
2004        let mut res = Vec::default();
2005        unsafe_operations(self.db, infer, def, store, block, &mut |node, _| {
2006            if let Ok(node) = sm.expr_or_pat_syntax(node) {
2007                res.push(node);
2008            }
2009        });
2010        res
2011    }
2012
2013    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
2014        let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
2015        if mac.is_asm_like(self.db) {
2016            return true;
2017        }
2018
2019        let Some(sa) = self.analyze(macro_call.syntax()) else { return false };
2020        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
2021        match macro_call.map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast)).transpose() {
2022            Some(it) => sa.is_unsafe_macro_call_expr(self.db, it.as_ref()),
2023            None => false,
2024        }
2025    }
2026
2027    pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
2028        let item_in_file = self.wrap_node_infile(item.clone());
2029        let id = self.with_ctx(|ctx| {
2030            let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?;
2031            macro_call_to_macro_id(ctx, macro_call_id)
2032        })?;
2033        Some(Macro { id })
2034    }
2035
2036    pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution<'db>> {
2037        self.resolve_path_with_subst(path).map(|(it, _)| it)
2038    }
2039
2040    pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option<PathResolutionPerNs<'db>> {
2041        self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path)
2042    }
2043
2044    pub fn resolve_path_with_subst(
2045        &self,
2046        path: &ast::Path,
2047    ) -> Option<(PathResolution<'db>, Option<GenericSubstitution<'db>>)> {
2048        self.analyze(path.syntax())?.resolve_path(self.db, path)
2049    }
2050
2051    pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<TypeParam> {
2052        self.analyze(name.syntax())?.resolve_use_type_arg(name)
2053    }
2054
2055    pub fn resolve_offset_of_field(
2056        &self,
2057        name_ref: &ast::NameRef,
2058    ) -> Option<(Either<EnumVariant, Field>, GenericSubstitution<'db>)> {
2059        self.analyze_no_infer(name_ref.syntax())?.resolve_offset_of_field(self.db, name_ref)
2060    }
2061
2062    pub fn resolve_mod_path(
2063        &self,
2064        scope: &SyntaxNode,
2065        path: &ModPath,
2066    ) -> Option<impl Iterator<Item = ItemInNs>> {
2067        let analyze = self.analyze(scope)?;
2068        let items = analyze.resolver.resolve_module_path_in_items(self.db, path);
2069        Some(items.iter_items().map(|(item, _)| item.into()))
2070    }
2071
2072    fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
2073        self.analyze(record_lit.syntax())?.resolve_variant(record_lit)
2074    }
2075
2076    pub fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
2077        self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
2078    }
2079
2080    pub fn record_literal_missing_fields(
2081        &self,
2082        literal: &ast::RecordExpr,
2083    ) -> Vec<(Field, Type<'db>)> {
2084        self.analyze(literal.syntax())
2085            .and_then(|it| it.record_literal_missing_fields(self.db, literal))
2086            .unwrap_or_default()
2087    }
2088
2089    pub fn record_literal_matched_fields(
2090        &self,
2091        literal: &ast::RecordExpr,
2092    ) -> Vec<(Field, Type<'db>)> {
2093        self.analyze(literal.syntax())
2094            .and_then(|it| it.record_literal_matched_fields(self.db, literal))
2095            .unwrap_or_default()
2096    }
2097
2098    pub fn record_pattern_missing_fields(
2099        &self,
2100        pattern: &ast::RecordPat,
2101    ) -> Vec<(Field, Type<'db>)> {
2102        self.analyze(pattern.syntax())
2103            .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
2104            .unwrap_or_default()
2105    }
2106
2107    pub fn record_pattern_matched_fields(
2108        &self,
2109        pattern: &ast::RecordPat,
2110    ) -> Vec<(Field, Type<'db>)> {
2111        self.analyze(pattern.syntax())
2112            .and_then(|it| it.record_pattern_matched_fields(self.db, pattern))
2113            .unwrap_or_default()
2114    }
2115
2116    fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'db, '_>) -> T, T>(&self, f: F) -> T {
2117        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut self.s2d_cache.borrow_mut() };
2118        f(&mut ctx)
2119    }
2120
2121    pub fn to_def<T: ToDef<'db>>(&self, src: &T) -> Option<T::Def> {
2122        let src = self.find_file(src.syntax()).with_value(src);
2123        T::to_def(self, src)
2124    }
2125
2126    pub fn to_def2<T: ToDef<'db>>(&self, src: InFile<&T>) -> Option<T::Def> {
2127        T::to_def(self, src)
2128    }
2129
2130    fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
2131        self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from)
2132    }
2133
2134    fn hir_file_to_module_defs(&self, file: HirFileId) -> impl Iterator<Item = Module> {
2135        // FIXME: Do we need to care about inline modules for macro expansions?
2136        self.file_to_module_defs(file.original_file_respecting_includes(self.db).file_id(self.db))
2137    }
2138
2139    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
2140        self.analyze_no_infer(node).map(
2141            |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope {
2142                db: self.db,
2143                file_id,
2144                resolver,
2145                infer_body,
2146            },
2147        )
2148    }
2149
2150    pub fn scope_at_offset(
2151        &self,
2152        node: &SyntaxNode,
2153        offset: TextSize,
2154    ) -> Option<SemanticsScope<'db>> {
2155        self.analyze_with_offset_no_infer(node, offset).map(
2156            |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope {
2157                db: self.db,
2158                file_id,
2159                resolver,
2160                infer_body,
2161            },
2162        )
2163    }
2164
2165    /// Search for a definition's source and cache its syntax tree
2166    pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> {
2167        // FIXME: source call should go through the parse cache
2168        let res = def.source(self.db)?;
2169        self.cache(res.value.syntax().tree_top(), res.file_id);
2170        Some(res)
2171    }
2172
2173    pub fn source_with_range<Def: HasSource>(
2174        &self,
2175        def: Def,
2176    ) -> Option<InFile<(TextRange, Option<Def::Ast>)>> {
2177        let res = def.source_with_range(self.db)?;
2178        self.parse_or_expand(res.file_id);
2179        Some(res)
2180    }
2181
2182    pub fn store_owner_for(&self, node: InFile<&SyntaxNode>) -> Option<ExpressionStoreOwner> {
2183        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2184        container.as_expression_store_owner().map(|id| id.into())
2185    }
2186
2187    fn populate_anon_const_cache_for<'a>(
2188        &self,
2189        cache: &'a mut DefAnonConstsMap<'db>,
2190        def: DefWithoutBodyWithAnonConsts,
2191    ) -> &'a ExprToAnonConst<'db> {
2192        cache.entry(def).or_insert_with(|| match def {
2193            Either::Left(def) => AnonConstId::all_from_signature(self.db, def)
2194                .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2195                .collect(),
2196            Either::Right(def) => {
2197                let all_anon_consts =
2198                    self.db.field_types_with_diagnostics(def).defined_anon_consts().iter().copied();
2199                all_anon_consts
2200                    .map(|anon_const| (anon_const.loc(self.db).expr, anon_const))
2201                    .collect()
2202            }
2203        })
2204    }
2205
2206    fn find_anon_const_for_root_expr_in_signature(
2207        &self,
2208        def: DefWithoutBodyWithAnonConsts,
2209        root_expr: ExprId,
2210    ) -> Option<AnonConstId<'db>> {
2211        let mut cache = self.signature_anon_consts_cache.borrow_mut();
2212        let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def);
2213        anon_consts_map.get(&root_expr).copied()
2214    }
2215
2216    pub(crate) fn infer_body_for_expr_or_pat(
2217        &self,
2218        def: ExpressionStoreOwnerId,
2219        store: &ExpressionStore,
2220        node: ExprOrPatId,
2221    ) -> Option<InferBodyId<'db>> {
2222        let handle_def_without_body = |def| {
2223            let root_expr = match node {
2224                ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr),
2225                ExprOrPatId::PatId(pat) => store.find_root_for_pat(pat),
2226            };
2227            let anon_const = self.find_anon_const_for_root_expr_in_signature(def, root_expr)?;
2228            Some(anon_const.into())
2229        };
2230        match def {
2231            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2232            ExpressionStoreOwnerId::Body(def) => Some(def.into()),
2233            ExpressionStoreOwnerId::VariantFields(def) => {
2234                handle_def_without_body(Either::Right(def))
2235            }
2236        }
2237    }
2238
2239    fn with_all_infers_for_store(
2240        &self,
2241        owner: ExpressionStoreOwnerId,
2242        callback: &mut dyn FnMut(&'db InferenceResult<'db>),
2243    ) {
2244        let mut handle_def_without_body = |def| {
2245            let mut cache = self.signature_anon_consts_cache.borrow_mut();
2246            let map = self.populate_anon_const_cache_for(&mut cache, def);
2247            for &anon_const in map.values() {
2248                callback(InferenceResult::of(self.db, anon_const));
2249            }
2250        };
2251        match owner {
2252            ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)),
2253            ExpressionStoreOwnerId::Body(def) => {
2254                callback(InferenceResult::of(self.db, def));
2255            }
2256            ExpressionStoreOwnerId::VariantFields(def) => {
2257                handle_def_without_body(Either::Right(def))
2258            }
2259        }
2260    }
2261
2262    /// Returns none if the file of the node is not part of a crate.
2263    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2264        let node = self.find_file(node);
2265        self.analyze_impl(node, None, true)
2266    }
2267
2268    /// Returns none if the file of the node is not part of a crate.
2269    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
2270        let node = self.find_file(node);
2271        self.analyze_impl(node, None, false)
2272    }
2273
2274    fn analyze_with_offset_no_infer(
2275        &self,
2276        node: &SyntaxNode,
2277        offset: TextSize,
2278    ) -> Option<SourceAnalyzer<'db>> {
2279        let node = self.find_file(node);
2280        self.analyze_impl(node, Some(offset), false)
2281    }
2282
2283    fn analyze_impl(
2284        &self,
2285        node: InFile<&SyntaxNode>,
2286        offset: Option<TextSize>,
2287        // replace this, just make the inference result a `LazyCell`
2288        infer: bool,
2289    ) -> Option<SourceAnalyzer<'db>> {
2290        let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
2291
2292        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2293
2294        let resolver = match container {
2295            ChildContainer::DefWithBodyId(def) => {
2296                return Some(if infer {
2297                    SourceAnalyzer::new_for_body(self.db, def, node, offset)
2298                } else {
2299                    SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
2300                });
2301            }
2302            ChildContainer::VariantId(def) => {
2303                return Some(SourceAnalyzer::new_variant_body(
2304                    self.db, self, def, node, offset, infer,
2305                ));
2306            }
2307            ChildContainer::TraitId(it) => {
2308                return Some(if infer {
2309                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2310                } else {
2311                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2312                });
2313            }
2314            ChildContainer::ImplId(it) => {
2315                return Some(if infer {
2316                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2317                } else {
2318                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2319                });
2320            }
2321            ChildContainer::EnumId(it) => {
2322                return Some(if infer {
2323                    SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset)
2324                } else {
2325                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset)
2326                });
2327            }
2328            ChildContainer::GenericDefId(it) => {
2329                return Some(if infer {
2330                    SourceAnalyzer::new_generic_def(self.db, self, it, node, offset)
2331                } else {
2332                    SourceAnalyzer::new_generic_def_no_infer(self.db, self, it, node, offset)
2333                });
2334            }
2335            ChildContainer::ModuleId(it) => it.resolver(self.db),
2336        };
2337        Some(SourceAnalyzer::new_for_resolver(resolver, node))
2338    }
2339
2340    fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
2341        SourceToDefCache::cache(
2342            &mut self.s2d_cache.borrow_mut().root_to_file_cache,
2343            root_node,
2344            file_id,
2345        );
2346    }
2347
2348    pub fn assert_contains_node(&self, node: &SyntaxNode) {
2349        self.find_file(node);
2350    }
2351
2352    fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
2353        let cache = self.s2d_cache.borrow();
2354        cache.root_to_file_cache.get(root_node).copied()
2355    }
2356
2357    fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> {
2358        let InFile { file_id, .. } = self.find_file(node.syntax());
2359        InFile::new(file_id, node)
2360    }
2361
2362    fn wrap_token_infile(&self, token: SyntaxToken) -> InFile<SyntaxToken> {
2363        let InFile { file_id, .. } = self.find_file(&token.parent().unwrap());
2364        InFile::new(file_id, token)
2365    }
2366
2367    /// Wraps the node in a [`InFile`] with the file id it belongs to.
2368    fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
2369        let root_node = node.tree_top();
2370        let file_id = self.lookup(&root_node).unwrap_or_else(|| {
2371            panic!(
2372                "\n\nFailed to lookup {:?} in this Semantics.\n\
2373                 Make sure to only query nodes derived from this instance of Semantics.\n\
2374                 root node:   {:?}\n\
2375                 known nodes: {}\n\n",
2376                node,
2377                root_node,
2378                self.s2d_cache
2379                    .borrow()
2380                    .root_to_file_cache
2381                    .keys()
2382                    .map(|it| format!("{it:?}"))
2383                    .collect::<Vec<_>>()
2384                    .join(", ")
2385            )
2386        });
2387        InFile::new(file_id, node)
2388    }
2389
2390    /// Returns `true` if the `node` is inside an `unsafe` context.
2391    pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
2392        let Some(enclosing_item) =
2393            expr.syntax().ancestors().find_map(Either::<ast::Item, ast::Variant>::cast)
2394        else {
2395            return false;
2396        };
2397
2398        let def = match &enclosing_item {
2399            Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
2400            Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id {
2401                AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)),
2402                AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
2403            })(),
2404            Either::Left(ast::Item::Const(it)) => {
2405                self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
2406            }
2407            Either::Left(ast::Item::Static(it)) => {
2408                self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
2409            }
2410            Either::Left(_) => None,
2411            Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
2412        };
2413        let Some(def) = def else { return false };
2414        let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
2415
2416        let (body, source_map) = Body::with_source_map(self.db, def);
2417
2418        let file_id = self.find_file(expr.syntax()).file_id;
2419
2420        let Some(mut parent) = expr.syntax().parent() else { return false };
2421        loop {
2422            if &parent == enclosing_node {
2423                break false;
2424            }
2425
2426            if let Some(parent) = ast::Expr::cast(parent.clone())
2427                && let Some(ExprOrPatId::ExprId(expr_id)) =
2428                    source_map.node_expr(InFile { file_id, value: &parent })
2429                && let Expr::Block { unsafe_: Unsafe::Yes, .. } = body[expr_id]
2430            {
2431                break true;
2432            }
2433
2434            let Some(parent_) = parent.parent() else { break false };
2435            parent = parent_;
2436        }
2437    }
2438
2439    pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
2440        let id = match impl_.id {
2441            AnyImplId::ImplId(id) => id,
2442            AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()),
2443        };
2444        let source = hir_def::src::HasSource::ast_ptr(id.loc(self.db), self.db);
2445        let mut file_id = source.file_id;
2446        let adt_ast_id = loop {
2447            let macro_call = file_id.macro_file()?;
2448            match macro_call.loc(self.db).kind {
2449                hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
2450                hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
2451                hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
2452            }
2453        };
2454        let adt_source = adt_ast_id.to_in_file_node(self.db);
2455        self.cache(adt_source.value.syntax().tree_top(), adt_source.file_id);
2456        ToDef::to_def(self, adt_source.as_ref())
2457    }
2458
2459    pub fn locals_used(
2460        &self,
2461        element: Either<&ast::Expr, &ast::StmtList>,
2462        text_range: TextRange,
2463    ) -> Option<FxIndexSet<Local<'db>>> {
2464        let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?;
2465        let infer_body = sa.infer_body?;
2466        let store = sa.store()?;
2467        let mut resolver = sa.resolver.clone();
2468        let def = resolver.expression_store_owner()?;
2469
2470        let is_not_generated = |path: &Path| {
2471            !path.mod_path().and_then(|path| path.as_ident()).is_some_and(Name::is_generated)
2472        };
2473
2474        let exprs = element.either(
2475            |e| vec![e.clone()],
2476            |stmts| {
2477                let mut exprs: Vec<_> = stmts
2478                    .statements()
2479                    .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
2480                    .filter_map(|stmt| match stmt {
2481                        ast::Stmt::ExprStmt(expr_stmt) => expr_stmt.expr().map(|e| vec![e]),
2482                        ast::Stmt::Item(_) => None,
2483                        ast::Stmt::LetStmt(let_stmt) => {
2484                            let init = let_stmt.initializer();
2485                            let let_else = let_stmt
2486                                .let_else()
2487                                .and_then(|le| le.block_expr())
2488                                .map(ast::Expr::BlockExpr);
2489
2490                            match (init, let_else) {
2491                                (Some(i), Some(le)) => Some(vec![i, le]),
2492                                (Some(i), _) => Some(vec![i]),
2493                                (_, Some(le)) => Some(vec![le]),
2494                                _ => None,
2495                            }
2496                        }
2497                    })
2498                    .flatten()
2499                    .collect();
2500
2501                if let Some(tail_expr) = stmts.tail_expr()
2502                    && text_range.contains_range(tail_expr.syntax().text_range())
2503                {
2504                    exprs.push(tail_expr);
2505                }
2506                exprs
2507            },
2508        );
2509        let mut exprs: Vec<_> =
2510            exprs.into_iter().filter_map(|e| sa.expr_id(e).and_then(|e| e.as_expr())).collect();
2511
2512        let mut locals: FxIndexSet<Local<'db>> = FxIndexSet::default();
2513        let mut add_to_locals_used = |id, parent_expr| {
2514            let path = match id {
2515                ExprOrPatId::ExprId(expr_id) => {
2516                    if let Expr::Path(path) = &store[expr_id] {
2517                        Some(path)
2518                    } else {
2519                        None
2520                    }
2521                }
2522                ExprOrPatId::PatId(_) => None,
2523            };
2524
2525            if let Some(path) = path
2526                && is_not_generated(path)
2527            {
2528                let _ = resolver.update_to_inner_scope(self.db, def, parent_expr);
2529                let hygiene = store.expr_or_pat_path_hygiene(id);
2530                resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).inspect(|value| {
2531                    if let ValueNs::LocalBinding(id) = value {
2532                        locals.insert(Local {
2533                            parent: def,
2534                            parent_infer: infer_body,
2535                            binding_id: *id,
2536                        });
2537                    }
2538                });
2539            }
2540        };
2541
2542        while let Some(expr_id) = exprs.pop() {
2543            if let Expr::Assignment { target, .. } = store[expr_id] {
2544                store.walk_pats(target, &mut |id| {
2545                    add_to_locals_used(ExprOrPatId::PatId(id), expr_id)
2546                });
2547            };
2548            store.walk_child_exprs(expr_id, |id| {
2549                exprs.push(id);
2550            });
2551
2552            add_to_locals_used(ExprOrPatId::ExprId(expr_id), expr_id)
2553        }
2554
2555        Some(locals)
2556    }
2557
2558    pub fn evaluate_where_clause_at(
2559        &self,
2560        node: &SyntaxNode,
2561        offset: TextSize,
2562        where_clause: ast::WhereClause,
2563    ) -> crate::PredicateEvaluationResult {
2564        let Some(analyzer) = self.analyze_with_offset_no_infer(node, offset) else {
2565            return crate::PredicateEvaluationResult::unsupported(
2566                "predicate evaluation is only supported in files that belong to a crate",
2567            );
2568        };
2569        analyzer.evaluate_where_clause(self.db, where_clause)
2570    }
2571
2572    pub fn get_failed_obligations(&self, token: SyntaxToken) -> Option<String> {
2573        let node = token.parent()?;
2574        let node = self.find_file(&node);
2575
2576        let container = self.with_ctx(|ctx| ctx.find_container(node))?;
2577
2578        match container {
2579            ChildContainer::DefWithBodyId(def) => {
2580                thread_local! {
2581                    static RESULT: RefCell<Vec<ProofTreeData>> = const { RefCell::new(Vec::new()) };
2582                }
2583                infer_query_with_inspect(
2584                    self.db,
2585                    def,
2586                    Some(|infer_ctxt, _obligation, result, proof_tree| {
2587                        if result.is_err()
2588                            && let Some(tree) = proof_tree
2589                        {
2590                            let data =
2591                                dump_proof_tree_structured(tree, hir_ty::Span::Dummy, infer_ctxt);
2592                            RESULT.with(|ctx| ctx.borrow_mut().push(data));
2593                        }
2594                    }),
2595                    LoweringMode::Ide,
2596                );
2597                let data: Vec<ProofTreeData> =
2598                    RESULT.with(|data| data.borrow_mut().drain(..).collect());
2599                let data = serde_json::to_string_pretty(&data).unwrap_or_else(|_| "[]".to_owned());
2600                Some(data)
2601            }
2602            _ => None,
2603        }
2604    }
2605}
2606
2607// FIXME This can't be the best way to do this
2608fn macro_call_to_macro_id(
2609    ctx: &mut SourceToDefCtx<'_, '_>,
2610    macro_call_id: MacroCallId,
2611) -> Option<MacroId> {
2612    let db = ctx.db;
2613    let loc = macro_call_id.loc(db);
2614
2615    match loc.def.ast_id() {
2616        Either::Left(it) => {
2617            let node = match it.file_id {
2618                HirFileId::FileId(file_id) => {
2619                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2620                }
2621                HirFileId::MacroFile(macro_file) => {
2622                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2623                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2624                }
2625            };
2626            ctx.macro_to_def(InFile::new(it.file_id, &node))
2627        }
2628        Either::Right(it) => {
2629            let node = match it.file_id {
2630                HirFileId::FileId(file_id) => {
2631                    it.to_ptr(db).to_node(&file_id.parse(db).syntax_node())
2632                }
2633                HirFileId::MacroFile(macro_file) => {
2634                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
2635                    it.to_ptr(db).to_node(&expansion_info.expanded().value)
2636                }
2637            };
2638            ctx.proc_macro_to_def(InFile::new(it.file_id, &node))
2639        }
2640    }
2641}
2642
2643pub trait ToDef<'db>: AstNode + Clone {
2644    type Def;
2645    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def>;
2646}
2647
2648macro_rules! to_def_impls {
2649    ($(($def:ty, $ast:path, $meth:ident)),* ,) => {$(
2650        impl<'db> ToDef<'db> for $ast {
2651            type Def = $def;
2652            fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2653                sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
2654            }
2655        }
2656    )*}
2657}
2658
2659to_def_impls![
2660    (crate::Module, ast::Module, module_to_def),
2661    (crate::Module, ast::SourceFile, source_file_to_def),
2662    (crate::Struct, ast::Struct, struct_to_def),
2663    (crate::Enum, ast::Enum, enum_to_def),
2664    (crate::Union, ast::Union, union_to_def),
2665    (crate::Trait, ast::Trait, trait_to_def),
2666    (crate::Impl, ast::Impl, impl_to_def),
2667    (crate::TypeAlias, ast::TypeAlias, type_alias_to_def),
2668    (crate::Const, ast::Const, const_to_def),
2669    (crate::Static, ast::Static, static_to_def),
2670    (crate::Function, ast::Fn, fn_to_def),
2671    (crate::Field, ast::RecordField, record_field_to_def),
2672    (crate::Field, ast::TupleField, tuple_field_to_def),
2673    (crate::EnumVariant, ast::Variant, enum_variant_to_def),
2674    (crate::TypeParam, ast::TypeParam, type_param_to_def),
2675    (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
2676    (crate::ConstParam, ast::ConstParam, const_param_to_def),
2677    (crate::GenericParam, ast::GenericParam, generic_param_to_def),
2678    (crate::Macro, ast::Macro, macro_to_def),
2679    (crate::Local<'db>, ast::SelfParam, self_param_to_def),
2680    (crate::Label, ast::Label, label_to_def),
2681    (crate::Adt, ast::Adt, adt_to_def),
2682    (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def),
2683    (crate::InlineAsmOperand, ast::AsmOperandNamed, asm_operand_to_def),
2684    (crate::ExternBlock, ast::ExternBlock, extern_block_to_def),
2685    (MacroCallId, ast::MacroCall, macro_call_to_macro_call),
2686];
2687
2688impl<'db> ToDef<'db> for ast::IdentPat {
2689    type Def = crate::Local<'db>;
2690
2691    fn to_def(sema: &SemanticsImpl<'db>, src: InFile<&Self>) -> Option<Self::Def> {
2692        sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema))
2693    }
2694}
2695
2696/// `SemanticsScope` encapsulates the notion of a scope (the set of visible
2697/// names) at a particular program point.
2698///
2699/// It is a bit tricky, as scopes do not really exist inside the compiler.
2700/// Rather, the compiler directly computes for each reference the definition it
2701/// refers to. It might transiently compute the explicit scope map while doing
2702/// so, but, generally, this is not something left after the analysis.
2703///
2704/// However, we do very much need explicit scopes for IDE purposes --
2705/// completion, at its core, lists the contents of the current scope. The notion
2706/// of scope is also useful to answer questions like "what would be the meaning
2707/// of this piece of code if we inserted it into this position?".
2708///
2709/// So `SemanticsScope` is constructed from a specific program point (a syntax
2710/// node or just a raw offset) and provides access to the set of visible names
2711/// on a somewhat best-effort basis.
2712///
2713/// Note that if you are wondering "what does this specific existing name mean?",
2714/// you'd better use the `resolve_` family of methods.
2715#[derive(Debug)]
2716pub struct SemanticsScope<'db> {
2717    pub db: &'db dyn HirDatabase,
2718    infer_body: Option<InferBodyId<'db>>,
2719    file_id: HirFileId,
2720    resolver: Resolver<'db>,
2721}
2722
2723impl<'db> SemanticsScope<'db> {
2724    pub fn file_id(&self) -> HirFileId {
2725        self.file_id
2726    }
2727
2728    pub fn module(&self) -> Module {
2729        Module { id: self.resolver.module() }
2730    }
2731
2732    pub fn krate(&self) -> Crate {
2733        Crate { id: self.resolver.krate() }
2734    }
2735
2736    // FIXME: This is a weird function, we shouldn't have this?
2737    pub fn containing_function(&self) -> Option<Function> {
2738        self.resolver.expression_store_owner().and_then(|owner| match owner {
2739            ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => Some(id.into()),
2740            _ => None,
2741        })
2742    }
2743
2744    pub fn expression_store_owner(&self) -> Option<ExpressionStoreOwner> {
2745        self.resolver.expression_store_owner().map(Into::into)
2746    }
2747
2748    pub(crate) fn resolver(&self) -> &Resolver<'db> {
2749        &self.resolver
2750    }
2751
2752    /// Note: `VisibleTraits` should be treated as an opaque type, passed into `Type
2753    pub fn visible_traits(&self) -> VisibleTraits {
2754        let resolver = &self.resolver;
2755        VisibleTraits(resolver.traits_in_scope(self.db))
2756    }
2757
2758    /// Calls the passed closure `f` on all names in scope.
2759    pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef<'db>)) {
2760        let scope = self.resolver.names_in_scope(self.db);
2761        for (name, entries) in scope {
2762            for entry in entries {
2763                let def = match entry {
2764                    resolver::ScopeDef::ModuleDef(it) => ScopeDef::ModuleDef(it.into()),
2765                    resolver::ScopeDef::Unknown => ScopeDef::Unknown,
2766                    resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
2767                    resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
2768                    resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
2769                    resolver::ScopeDef::Local(binding_id) => {
2770                        match (self.resolver.expression_store_owner(), self.infer_body) {
2771                            (Some(parent), Some(parent_infer)) => {
2772                                ScopeDef::Local(Local { parent, parent_infer, binding_id })
2773                            }
2774                            _ => continue,
2775                        }
2776                    }
2777                    resolver::ScopeDef::Label(label_id) => {
2778                        match self.resolver.expression_store_owner() {
2779                            Some(parent) => ScopeDef::Label(Label { parent, label_id }),
2780                            None => continue,
2781                        }
2782                    }
2783                };
2784                f(name.clone(), def)
2785            }
2786        }
2787    }
2788
2789    /// Checks if a trait is in scope, either because of an import or because we're in an impl of it.
2790    pub fn can_use_trait_methods(&self, t: Trait) -> bool {
2791        self.resolver.traits_in_scope(self.db).contains(&t.id)
2792    }
2793
2794    /// Resolve a path as-if it was written at the given scope. This is
2795    /// necessary a heuristic, as it doesn't take hygiene into account.
2796    pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution<'db>> {
2797        let mut kind = PathKind::Plain;
2798        let mut segments = vec![];
2799        let mut first = true;
2800        for segment in ast_path.segments() {
2801            if first {
2802                first = false;
2803                if segment.coloncolon_token().is_some() {
2804                    kind = PathKind::Abs;
2805                }
2806            }
2807
2808            let Some(k) = segment.kind() else { continue };
2809            match k {
2810                ast::PathSegmentKind::Name(name_ref) => segments.push(name_ref.as_name()),
2811                ast::PathSegmentKind::Type { .. } => continue,
2812                ast::PathSegmentKind::SelfTypeKw => {
2813                    segments.push(Name::new_symbol_root(sym::Self_))
2814                }
2815                ast::PathSegmentKind::SelfKw => kind = PathKind::Super(0),
2816                ast::PathSegmentKind::SuperKw => match kind {
2817                    PathKind::Super(s) => kind = PathKind::Super(s + 1),
2818                    PathKind::Plain => kind = PathKind::Super(1),
2819                    PathKind::Crate | PathKind::Abs | PathKind::DollarCrate(_) => continue,
2820                },
2821                ast::PathSegmentKind::CrateKw => kind = PathKind::Crate,
2822            }
2823        }
2824
2825        resolve_hir_path(
2826            self.db,
2827            &self.resolver,
2828            self.infer_body,
2829            &Path::BarePath(Interned::new(ModPath::from_segments(kind, segments))),
2830            HygieneId::ROOT,
2831            None,
2832        )
2833    }
2834
2835    pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> + use<> {
2836        let items = self.resolver.resolve_module_path_in_items(self.db, path);
2837        items.iter_items().map(|(item, _)| item.into())
2838    }
2839
2840    /// Iterates over associated types that may be specified after the given path (using
2841    /// `Ty::Assoc` syntax).
2842    pub fn assoc_type_shorthand_candidates(
2843        &self,
2844        resolution: &PathResolution<'db>,
2845        mut cb: impl FnMut(TypeAlias),
2846    ) {
2847        let (Some(def), Some(resolution)) = (self.resolver.generic_def(), resolution.in_type_ns())
2848        else {
2849            return;
2850        };
2851        hir_ty::associated_type_shorthand_candidates(self.db, def, resolution, |_, id| {
2852            cb(id.into());
2853            false
2854        });
2855    }
2856
2857    pub fn generic_def(&self) -> Option<crate::GenericDef> {
2858        self.resolver.generic_def().map(|id| id.into())
2859    }
2860
2861    pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ {
2862        self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id }))
2863    }
2864
2865    pub fn extern_crate_decls(&self) -> impl Iterator<Item = Name> + '_ {
2866        self.resolver.extern_crate_decls_in_scope(self.db)
2867    }
2868
2869    pub fn has_same_self_type(&self, other: &SemanticsScope<'_>) -> bool {
2870        self.resolver.impl_def() == other.resolver.impl_def()
2871    }
2872}
2873
2874#[derive(Debug)]
2875pub struct VisibleTraits(pub FxHashSet<TraitId>);
2876
2877impl ops::Deref for VisibleTraits {
2878    type Target = FxHashSet<TraitId>;
2879
2880    fn deref(&self) -> &Self::Target {
2881        &self.0
2882    }
2883}
2884
2885struct RenameConflictsVisitor<'a> {
2886    db: &'a dyn HirDatabase,
2887    owner: ExpressionStoreOwnerId,
2888    resolver: Resolver<'a>,
2889    body: &'a ExpressionStore,
2890    to_be_renamed: BindingId,
2891    new_name: Symbol,
2892    old_name: Symbol,
2893    conflicts: FxHashSet<BindingId>,
2894}
2895
2896impl RenameConflictsVisitor<'_> {
2897    fn resolve_path(&mut self, node: ExprOrPatId, path: &Path) {
2898        if let Path::BarePath(path) = path
2899            && let Some(name) = path.as_ident()
2900        {
2901            if *name.symbol() == self.new_name {
2902                if let Some(conflicting) = self.resolver.rename_will_conflict_with_renamed(
2903                    self.db,
2904                    name,
2905                    path,
2906                    self.body.expr_or_pat_path_hygiene(node),
2907                    self.to_be_renamed,
2908                ) {
2909                    self.conflicts.insert(conflicting);
2910                }
2911            } else if *name.symbol() == self.old_name
2912                && let Some(conflicting) = self.resolver.rename_will_conflict_with_another_variable(
2913                    self.db,
2914                    name,
2915                    path,
2916                    self.body.expr_or_pat_path_hygiene(node),
2917                    &self.new_name,
2918                    self.to_be_renamed,
2919                )
2920            {
2921                self.conflicts.insert(conflicting);
2922            }
2923        }
2924    }
2925
2926    fn rename_conflicts(&mut self, expr: ExprId) {
2927        match &self.body[expr] {
2928            Expr::Path(path) => {
2929                let guard = self.resolver.update_to_inner_scope(self.db, self.owner, expr);
2930                self.resolve_path(expr.into(), path);
2931                self.resolver.reset_to_guard(guard);
2932            }
2933            _ => {}
2934        }
2935
2936        self.body.walk_child_exprs(expr, |expr| self.rename_conflicts(expr));
2937    }
2938}