]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / hir / src / source_analyzer.rs
CommitLineData
064997fb
FG
1//! Lookup hir elements using positions in the source code. This is a lossy
2//! transformation: in general, a single source might correspond to several
3//! modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
4//! modules.
5//!
6//! So, this modules should not be used during hir construction, it exists
7//! purely for "IDE needs".
8use std::{
9 iter::{self, once},
10 sync::Arc,
11};
12
13use hir_def::{
14 body::{
15 self,
16 scope::{ExprScopes, ScopeId},
17 Body, BodySourceMap,
18 },
19 expr::{ExprId, Pat, PatId},
20 macro_id_to_def_id,
21 path::{ModPath, Path, PathKind},
22 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
23 type_ref::Mutability,
9c376795
FG
24 AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
25 LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
064997fb
FG
26};
27use hir_expand::{
f2b60f7d
FG
28 builtin_fn_macro::BuiltinFnLikeExpander,
29 hygiene::Hygiene,
30 mod_path::path,
31 name,
32 name::{AsName, Name},
33 HirFileId, InFile,
064997fb
FG
34};
35use hir_ty::{
36 diagnostics::{
37 record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
38 UnsafeExpr,
39 },
f2b60f7d 40 method_resolution::{self, lang_names_for_bin_op},
487cf647 41 Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
064997fb
FG
42};
43use itertools::Itertools;
44use smallvec::SmallVec;
45use syntax::{
46 ast::{self, AstNode},
47 SyntaxKind, SyntaxNode, TextRange, TextSize,
48};
49
50use crate::{
51 db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
52 BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
53 Struct, ToolModule, Trait, Type, TypeAlias, Variant,
54};
55
56/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
57/// original source files. It should not be used inside the HIR itself.
58#[derive(Debug)]
59pub(crate) struct SourceAnalyzer {
60 pub(crate) file_id: HirFileId,
61 pub(crate) resolver: Resolver,
62 def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
63 infer: Option<Arc<InferenceResult>>,
64}
65
66impl SourceAnalyzer {
67 pub(crate) fn new_for_body(
68 db: &dyn HirDatabase,
69 def: DefWithBodyId,
70 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
71 offset: Option<TextSize>,
72 ) -> SourceAnalyzer {
73 let (body, source_map) = db.body_with_source_map(def);
74 let scopes = db.expr_scopes(def);
75 let scope = match offset {
76 None => scope_for(&scopes, &source_map, node),
77 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
78 };
79 let resolver = resolver_for_scope(db.upcast(), def, scope);
80 SourceAnalyzer {
81 resolver,
82 def: Some((def, body, source_map)),
83 infer: Some(db.infer(def)),
84 file_id,
85 }
86 }
87
88 pub(crate) fn new_for_body_no_infer(
89 db: &dyn HirDatabase,
90 def: DefWithBodyId,
91 node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
92 offset: Option<TextSize>,
93 ) -> SourceAnalyzer {
94 let (body, source_map) = db.body_with_source_map(def);
95 let scopes = db.expr_scopes(def);
96 let scope = match offset {
97 None => scope_for(&scopes, &source_map, node),
98 Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset),
99 };
100 let resolver = resolver_for_scope(db.upcast(), def, scope);
101 SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
102 }
103
104 pub(crate) fn new_for_resolver(
105 resolver: Resolver,
106 node: InFile<&SyntaxNode>,
107 ) -> SourceAnalyzer {
108 SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
109 }
110
111 fn body_source_map(&self) -> Option<&BodySourceMap> {
112 self.def.as_ref().map(|(.., source_map)| &**source_map)
113 }
114 fn body(&self) -> Option<&Body> {
115 self.def.as_ref().map(|(_, body, _)| &**body)
116 }
117
118 fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
119 let src = match expr {
120 ast::Expr::MacroExpr(expr) => {
9c376795 121 self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
064997fb
FG
122 }
123 _ => InFile::new(self.file_id, expr.clone()),
124 };
125 let sm = self.body_source_map()?;
126 sm.node_expr(src.as_ref())
127 }
128
129 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
130 // FIXME: macros, see `expr_id`
131 let src = InFile { file_id: self.file_id, value: pat };
132 self.body_source_map()?.node_pat(src)
133 }
134
135 fn expand_expr(
136 &self,
137 db: &dyn HirDatabase,
138 expr: InFile<ast::MacroCall>,
139 ) -> Option<InFile<ast::Expr>> {
140 let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
141 let expanded = db.parse_or_expand(macro_file)?;
f2b60f7d
FG
142 let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
143 match stmts.expr()? {
144 ast::Expr::MacroExpr(mac) => {
145 self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
146 }
147 expr => InFile::new(macro_file, expr),
148 }
149 } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
150 self.expand_expr(db, InFile::new(macro_file, call))?
151 } else {
152 InFile::new(macro_file, ast::Expr::cast(expanded)?)
064997fb 153 };
f2b60f7d 154
064997fb
FG
155 Some(res)
156 }
157
487cf647 158 pub(crate) fn expr_adjustments(
064997fb
FG
159 &self,
160 db: &dyn HirDatabase,
161 expr: &ast::Expr,
487cf647 162 ) -> Option<&[Adjustment]> {
064997fb
FG
163 let expr_id = self.expr_id(db, expr)?;
164 let infer = self.infer.as_ref()?;
487cf647 165 infer.expr_adjustments.get(&expr_id).map(|v| &**v)
064997fb
FG
166 }
167
168 pub(crate) fn type_of_expr(
169 &self,
170 db: &dyn HirDatabase,
171 expr: &ast::Expr,
172 ) -> Option<(Type, Option<Type>)> {
173 let expr_id = self.expr_id(db, expr)?;
174 let infer = self.infer.as_ref()?;
175 let coerced = infer
176 .expr_adjustments
177 .get(&expr_id)
178 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
179 let ty = infer[expr_id].clone();
180 let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
181 Some((mk_ty(ty), coerced.map(mk_ty)))
182 }
183
184 pub(crate) fn type_of_pat(
185 &self,
186 db: &dyn HirDatabase,
187 pat: &ast::Pat,
188 ) -> Option<(Type, Option<Type>)> {
189 let pat_id = self.pat_id(pat)?;
190 let infer = self.infer.as_ref()?;
191 let coerced = infer
192 .pat_adjustments
193 .get(&pat_id)
194 .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
195 let ty = infer[pat_id].clone();
196 let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
197 Some((mk_ty(ty), coerced.map(mk_ty)))
198 }
199
200 pub(crate) fn type_of_self(
201 &self,
202 db: &dyn HirDatabase,
203 param: &ast::SelfParam,
204 ) -> Option<Type> {
205 let src = InFile { file_id: self.file_id, value: param };
206 let pat_id = self.body_source_map()?.node_self_param(src)?;
207 let ty = self.infer.as_ref()?[pat_id].clone();
208 Some(Type::new_with_resolver(db, &self.resolver, ty))
209 }
210
211 pub(crate) fn binding_mode_of_pat(
212 &self,
213 _db: &dyn HirDatabase,
214 pat: &ast::IdentPat,
215 ) -> Option<BindingMode> {
216 let pat_id = self.pat_id(&pat.clone().into())?;
217 let infer = self.infer.as_ref()?;
218 infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
219 hir_ty::BindingMode::Move => BindingMode::Move,
220 hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
221 hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
222 BindingMode::Ref(Mutability::Shared)
223 }
224 })
225 }
226 pub(crate) fn pattern_adjustments(
227 &self,
228 db: &dyn HirDatabase,
229 pat: &ast::Pat,
230 ) -> Option<SmallVec<[Type; 1]>> {
9c376795 231 let pat_id = self.pat_id(pat)?;
064997fb
FG
232 let infer = self.infer.as_ref()?;
233 Some(
234 infer
235 .pat_adjustments
236 .get(&pat_id)?
237 .iter()
238 .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
239 .collect(),
240 )
241 }
242
243 pub(crate) fn resolve_method_call_as_callable(
244 &self,
245 db: &dyn HirDatabase,
246 call: &ast::MethodCallExpr,
247 ) -> Option<Callable> {
248 let expr_id = self.expr_id(db, &call.clone().into())?;
249 let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
250 let ty = db.value_ty(func.into()).substitute(Interner, &substs);
251 let ty = Type::new_with_resolver(db, &self.resolver, ty);
252 let mut res = ty.as_callable(db)?;
253 res.is_bound_method = true;
254 Some(res)
255 }
256
257 pub(crate) fn resolve_method_call(
258 &self,
259 db: &dyn HirDatabase,
260 call: &ast::MethodCallExpr,
261 ) -> Option<FunctionId> {
262 let expr_id = self.expr_id(db, &call.clone().into())?;
263 let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
f2b60f7d 264
487cf647 265 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
f2b60f7d
FG
266 }
267
268 pub(crate) fn resolve_await_to_poll(
269 &self,
270 db: &dyn HirDatabase,
271 await_expr: &ast::AwaitExpr,
272 ) -> Option<FunctionId> {
9c376795 273 let mut ty = self.ty_of_expr(db, &await_expr.expr()?)?.clone();
f2b60f7d
FG
274
275 let into_future_trait = self
276 .resolver
277 .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
278 .map(Trait::from);
279
280 if let Some(into_future_trait) = into_future_trait {
281 let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
282 if type_.impls_trait(db, into_future_trait, &[]) {
283 let items = into_future_trait.items(db);
284 let into_future_type = items.into_iter().find_map(|item| match item {
285 AssocItem::TypeAlias(alias)
286 if alias.name(db) == hir_expand::name![IntoFuture] =>
287 {
288 Some(alias)
289 }
290 _ => None,
291 })?;
292 let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
293 ty = future_trait.ty;
294 }
295 }
296
2b03887a
FG
297 let future_trait = db
298 .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
299 .as_trait()?;
f2b60f7d
FG
300 let poll_fn = db
301 .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
302 .as_function()?;
2b03887a
FG
303 // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
304 // doesn't have any generic parameters, so we skip building another subst for `poll()`.
305 let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
487cf647 306 Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
f2b60f7d
FG
307 }
308
309 pub(crate) fn resolve_prefix_expr(
310 &self,
311 db: &dyn HirDatabase,
312 prefix_expr: &ast::PrefixExpr,
313 ) -> Option<FunctionId> {
314 let lang_item_name = match prefix_expr.op_kind()? {
315 ast::UnaryOp::Deref => name![deref],
316 ast::UnaryOp::Not => name![not],
317 ast::UnaryOp::Neg => name![neg],
318 };
9c376795 319 let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
f2b60f7d 320
2b03887a
FG
321 let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
322 // HACK: subst for all methods coincides with that for their trait because the methods
323 // don't have any generic parameters, so we skip building another subst for the methods.
324 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
f2b60f7d 325
487cf647 326 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
327 }
328
329 pub(crate) fn resolve_index_expr(
330 &self,
331 db: &dyn HirDatabase,
332 index_expr: &ast::IndexExpr,
333 ) -> Option<FunctionId> {
9c376795
FG
334 let base_ty = self.ty_of_expr(db, &index_expr.base()?)?;
335 let index_ty = self.ty_of_expr(db, &index_expr.index()?)?;
f2b60f7d
FG
336
337 let lang_item_name = name![index];
338
2b03887a
FG
339 let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
340 // HACK: subst for all methods coincides with that for their trait because the methods
341 // don't have any generic parameters, so we skip building another subst for the methods.
342 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
f2b60f7d
FG
343 .push(base_ty.clone())
344 .push(index_ty.clone())
345 .build();
487cf647 346 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
347 }
348
349 pub(crate) fn resolve_bin_expr(
350 &self,
351 db: &dyn HirDatabase,
352 binop_expr: &ast::BinExpr,
353 ) -> Option<FunctionId> {
354 let op = binop_expr.op_kind()?;
9c376795
FG
355 let lhs = self.ty_of_expr(db, &binop_expr.lhs()?)?;
356 let rhs = self.ty_of_expr(db, &binop_expr.rhs()?)?;
f2b60f7d 357
2b03887a 358 let (op_trait, op_fn) = lang_names_for_bin_op(op)
f2b60f7d 359 .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
2b03887a
FG
360 // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
361 // doesn't have any generic parameters, so we skip building another subst for `index()`.
362 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
363 .push(lhs.clone())
364 .push(rhs.clone())
365 .build();
f2b60f7d 366
487cf647 367 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
f2b60f7d
FG
368 }
369
370 pub(crate) fn resolve_try_expr(
371 &self,
372 db: &dyn HirDatabase,
373 try_expr: &ast::TryExpr,
374 ) -> Option<FunctionId> {
9c376795 375 let ty = self.ty_of_expr(db, &try_expr.expr()?)?;
f2b60f7d
FG
376
377 let op_fn =
378 db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
2b03887a
FG
379 let op_trait = match op_fn.lookup(db.upcast()).container {
380 ItemContainerId::TraitId(id) => id,
381 _ => return None,
382 };
383 // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
384 // doesn't have any generic parameters, so we skip building another subst for `branch()`.
385 let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
f2b60f7d 386
487cf647 387 Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
064997fb
FG
388 }
389
390 pub(crate) fn resolve_field(
391 &self,
392 db: &dyn HirDatabase,
393 field: &ast::FieldExpr,
394 ) -> Option<Field> {
395 let expr_id = self.expr_id(db, &field.clone().into())?;
396 self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
397 }
398
399 pub(crate) fn resolve_record_field(
400 &self,
401 db: &dyn HirDatabase,
402 field: &ast::RecordExprField,
403 ) -> Option<(Field, Option<Local>, Type)> {
404 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
405 let expr = ast::Expr::from(record_expr);
406 let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
407
408 let local_name = field.field_name()?.as_name();
409 let local = if field.name_ref().is_some() {
410 None
411 } else {
f2b60f7d 412 // Shorthand syntax, resolve to the local
064997fb
FG
413 let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
414 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
415 Some(ValueNs::LocalBinding(pat_id)) => {
416 Some(Local { pat_id, parent: self.resolver.body_owner()? })
417 }
418 _ => None,
419 }
420 };
421 let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
422 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
423 let variant_data = variant.variant_data(db.upcast());
424 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
425 let field_ty =
426 db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
427 Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
428 }
429
430 pub(crate) fn resolve_record_pat_field(
431 &self,
432 db: &dyn HirDatabase,
433 field: &ast::RecordPatField,
434 ) -> Option<Field> {
435 let field_name = field.field_name()?.as_name();
436 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
437 let pat_id = self.pat_id(&record_pat.into())?;
438 let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
439 let variant_data = variant.variant_data(db.upcast());
440 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
441 Some(field.into())
442 }
443
444 pub(crate) fn resolve_macro_call(
445 &self,
446 db: &dyn HirDatabase,
447 macro_call: InFile<&ast::MacroCall>,
448 ) -> Option<Macro> {
449 let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
450 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
451 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
452 }
453
454 pub(crate) fn resolve_bind_pat_to_const(
455 &self,
456 db: &dyn HirDatabase,
457 pat: &ast::IdentPat,
458 ) -> Option<ModuleDef> {
459 let pat_id = self.pat_id(&pat.clone().into())?;
460 let body = self.body()?;
461 let path = match &body[pat_id] {
462 Pat::Path(path) => path,
463 _ => return None,
464 };
465 let res = resolve_hir_path(db, &self.resolver, path)?;
466 match res {
467 PathResolution::Def(def) => Some(def),
468 _ => None,
469 }
470 }
471
472 pub(crate) fn resolve_path(
473 &self,
474 db: &dyn HirDatabase,
475 path: &ast::Path,
476 ) -> Option<PathResolution> {
477 let parent = path.syntax().parent();
478 let parent = || parent.clone();
479
480 let mut prefer_value_ns = false;
481 let resolved = (|| {
487cf647 482 let infer = self.infer.as_deref()?;
064997fb
FG
483 if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
484 let expr_id = self.expr_id(db, &path_expr.into())?;
9c376795 485 if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
064997fb
FG
486 let assoc = match assoc {
487 AssocItemId::FunctionId(f_in_trait) => {
488 match infer.type_of_expr.get(expr_id) {
489 None => assoc,
490 Some(func_ty) => {
491 if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
487cf647
FG
492 self.resolve_impl_method_or_trait_def(
493 db,
494 f_in_trait,
495 subs.clone(),
496 )
497 .into()
064997fb
FG
498 } else {
499 assoc
500 }
501 }
502 }
503 }
9c376795
FG
504 AssocItemId::ConstId(const_id) => {
505 self.resolve_impl_const_or_trait_def(db, const_id, subs).into()
506 }
064997fb
FG
507 _ => assoc,
508 };
509
510 return Some(PathResolution::Def(AssocItem::from(assoc).into()));
511 }
512 if let Some(VariantId::EnumVariantId(variant)) =
513 infer.variant_resolution_for_expr(expr_id)
514 {
515 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
516 }
517 prefer_value_ns = true;
518 } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
519 let pat_id = self.pat_id(&path_pat.into())?;
9c376795 520 if let Some((assoc, _)) = infer.assoc_resolutions_for_pat(pat_id) {
064997fb
FG
521 return Some(PathResolution::Def(AssocItem::from(assoc).into()));
522 }
523 if let Some(VariantId::EnumVariantId(variant)) =
487cf647 524 infer.variant_resolution_for_pat(pat_id)
064997fb
FG
525 {
526 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
527 }
528 } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
529 let expr_id = self.expr_id(db, &rec_lit.into())?;
530 if let Some(VariantId::EnumVariantId(variant)) =
487cf647 531 infer.variant_resolution_for_expr(expr_id)
064997fb
FG
532 {
533 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
534 }
535 } else {
536 let record_pat = parent().and_then(ast::RecordPat::cast).map(ast::Pat::from);
537 let tuple_struct_pat =
538 || parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
539 if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
540 let pat_id = self.pat_id(&pat)?;
487cf647 541 let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id);
064997fb
FG
542 if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
543 return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
544 }
545 }
546 }
547 None
548 })();
549 if let Some(_) = resolved {
550 return resolved;
551 }
552
553 // This must be a normal source file rather than macro file.
554 let hygiene = Hygiene::new(db.upcast(), self.file_id);
555 let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
556 let hir_path = Path::from_src(path.clone(), &ctx)?;
557
558 // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
559 // trying to resolve foo::bar.
560 if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
561 if use_tree.coloncolon_token().is_some() {
562 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
563 }
564 }
565
566 let meta_path = path
567 .syntax()
568 .ancestors()
569 .take_while(|it| {
570 let kind = it.kind();
571 ast::Path::can_cast(kind) || ast::Meta::can_cast(kind)
572 })
573 .last()
574 .and_then(ast::Meta::cast);
575
576 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
577 // trying to resolve foo::bar.
578 if path.parent_path().is_some() {
579 return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
580 None if meta_path.is_some() => {
581 path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
582 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
583 .map(PathResolution::ToolModule)
584 })
585 }
586 res => res,
587 };
588 } else if let Some(meta_path) = meta_path {
589 // Case where we are resolving the final path segment of a path in an attribute
590 // in this case we have to check for inert/builtin attributes and tools and prioritize
591 // resolution of attributes over other namespaces
592 if let Some(name_ref) = path.as_single_name_ref() {
593 let builtin =
594 BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text());
595 if let Some(_) = builtin {
596 return builtin.map(PathResolution::BuiltinAttr);
597 }
598
599 if let Some(attr) = meta_path.parent_attr() {
600 let adt = if let Some(field) =
601 attr.syntax().parent().and_then(ast::RecordField::cast)
602 {
603 field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
604 } else if let Some(field) =
605 attr.syntax().parent().and_then(ast::TupleField::cast)
606 {
607 field.syntax().ancestors().take(4).find_map(ast::Adt::cast)
608 } else if let Some(variant) =
609 attr.syntax().parent().and_then(ast::Variant::cast)
610 {
611 variant.syntax().ancestors().nth(2).and_then(ast::Adt::cast)
612 } else {
613 None
614 };
615 if let Some(adt) = adt {
616 let ast_id = db.ast_id_map(self.file_id).ast_id(&adt);
617 if let Some(helpers) = self
618 .resolver
619 .def_map()
620 .derive_helpers_in_scope(InFile::new(self.file_id, ast_id))
621 {
622 // FIXME: Multiple derives can have the same helper
623 let name_ref = name_ref.as_name();
624 for (macro_id, mut helpers) in
625 helpers.iter().group_by(|(_, macro_id, ..)| macro_id).into_iter()
626 {
627 if let Some(idx) = helpers.position(|(name, ..)| *name == name_ref)
628 {
629 return Some(PathResolution::DeriveHelper(DeriveHelper {
630 derive: *macro_id,
631 idx,
632 }));
633 }
634 }
635 }
636 }
637 }
638 }
639 return match resolve_hir_path_as_macro(db, &self.resolver, &hir_path) {
640 Some(m) => Some(PathResolution::Def(ModuleDef::Macro(m))),
641 // this labels any path that starts with a tool module as the tool itself, this is technically wrong
642 // but there is no benefit in differentiating these two cases for the time being
643 None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
644 ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
645 .map(PathResolution::ToolModule)
646 }),
647 };
648 }
649 if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
650 resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
651 } else {
652 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
653 }
654 }
655
656 pub(crate) fn record_literal_missing_fields(
657 &self,
658 db: &dyn HirDatabase,
659 literal: &ast::RecordExpr,
660 ) -> Option<Vec<(Field, Type)>> {
661 let body = self.body()?;
662 let infer = self.infer.as_ref()?;
663
664 let expr_id = self.expr_id(db, &literal.clone().into())?;
665 let substs = infer.type_of_expr[expr_id].as_adt()?.1;
666
667 let (variant, missing_fields, _exhaustive) =
668 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
669 let res = self.missing_fields(db, substs, variant, missing_fields);
670 Some(res)
671 }
672
673 pub(crate) fn record_pattern_missing_fields(
674 &self,
675 db: &dyn HirDatabase,
676 pattern: &ast::RecordPat,
677 ) -> Option<Vec<(Field, Type)>> {
678 let body = self.body()?;
679 let infer = self.infer.as_ref()?;
680
681 let pat_id = self.pat_id(&pattern.clone().into())?;
682 let substs = infer.type_of_pat[pat_id].as_adt()?.1;
683
684 let (variant, missing_fields, _exhaustive) =
685 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
686 let res = self.missing_fields(db, substs, variant, missing_fields);
687 Some(res)
688 }
689
690 fn missing_fields(
691 &self,
692 db: &dyn HirDatabase,
693 substs: &Substitution,
694 variant: VariantId,
695 missing_fields: Vec<LocalFieldId>,
696 ) -> Vec<(Field, Type)> {
697 let field_types = db.field_types(variant);
698
699 missing_fields
700 .into_iter()
701 .map(|local_id| {
702 let field = FieldId { parent: variant, local_id };
703 let ty = field_types[local_id].clone().substitute(Interner, substs);
704 (field.into(), Type::new_with_resolver_inner(db, &self.resolver, ty))
705 })
706 .collect()
707 }
708
709 pub(crate) fn expand(
710 &self,
711 db: &dyn HirDatabase,
712 macro_call: InFile<&ast::MacroCall>,
713 ) -> Option<HirFileId> {
714 let krate = self.resolver.krate();
715 let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
716 self.resolver
717 .resolve_path_as_macro(db.upcast(), &path)
718 .map(|it| macro_id_to_def_id(db.upcast(), it))
719 })?;
720 Some(macro_call_id.as_file()).filter(|it| it.expansion_level(db.upcast()) < 64)
721 }
722
723 pub(crate) fn resolve_variant(
724 &self,
725 db: &dyn HirDatabase,
726 record_lit: ast::RecordExpr,
727 ) -> Option<VariantId> {
728 let infer = self.infer.as_ref()?;
729 let expr_id = self.expr_id(db, &record_lit.into())?;
730 infer.variant_resolution_for_expr(expr_id)
731 }
732
733 pub(crate) fn is_unsafe_macro_call(
734 &self,
735 db: &dyn HirDatabase,
736 macro_call: InFile<&ast::MacroCall>,
737 ) -> bool {
738 // check for asm/global_asm
739 if let Some(mac) = self.resolve_macro_call(db, macro_call) {
740 let ex = match mac.id {
741 hir_def::MacroId::Macro2Id(it) => it.lookup(db.upcast()).expander,
742 hir_def::MacroId::MacroRulesId(it) => it.lookup(db.upcast()).expander,
743 _ => hir_def::MacroExpander::Declarative,
744 };
745 match ex {
746 hir_def::MacroExpander::BuiltIn(e)
747 if e == BuiltinFnLikeExpander::Asm || e == BuiltinFnLikeExpander::GlobalAsm =>
748 {
749 return true
750 }
751 _ => (),
752 }
753 }
754 let macro_expr = match macro_call
755 .map(|it| it.syntax().parent().and_then(ast::MacroExpr::cast))
756 .transpose()
757 {
758 Some(it) => it,
759 None => return false,
760 };
761
762 if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
763 if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr.as_ref()) {
764 let mut is_unsafe = false;
765 unsafe_expressions(
766 db,
767 infer,
768 *def,
769 body,
770 expanded_expr,
771 &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
772 );
773 return is_unsafe;
774 }
775 }
776 false
777 }
778
487cf647 779 fn resolve_impl_method_or_trait_def(
064997fb
FG
780 &self,
781 db: &dyn HirDatabase,
782 func: FunctionId,
487cf647
FG
783 substs: Substitution,
784 ) -> FunctionId {
064997fb 785 let krate = self.resolver.krate();
487cf647
FG
786 let owner = match self.resolver.body_owner() {
787 Some(it) => it,
788 None => return func,
789 };
790 let env = owner.as_generic_def_id().map_or_else(
064997fb
FG
791 || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
792 |d| db.trait_environment(d),
793 );
487cf647 794 method_resolution::lookup_impl_method(db, env, func, substs)
f2b60f7d
FG
795 }
796
9c376795
FG
797 fn resolve_impl_const_or_trait_def(
798 &self,
799 db: &dyn HirDatabase,
800 const_id: ConstId,
801 subs: Substitution,
802 ) -> ConstId {
803 let krate = self.resolver.krate();
804 let owner = match self.resolver.body_owner() {
805 Some(it) => it,
806 None => return const_id,
807 };
808 let env = owner.as_generic_def_id().map_or_else(
809 || Arc::new(hir_ty::TraitEnvironment::empty(krate)),
810 |d| db.trait_environment(d),
811 );
812 method_resolution::lookup_impl_const(db, env, const_id, subs)
813 }
814
f2b60f7d
FG
815 fn lang_trait_fn(
816 &self,
817 db: &dyn HirDatabase,
818 lang_trait: &Name,
819 method_name: &Name,
2b03887a
FG
820 ) -> Option<(TraitId, FunctionId)> {
821 let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
822 let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
823 Some((trait_id, fn_id))
f2b60f7d
FG
824 }
825
826 fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
9c376795 827 self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
f2b60f7d 828 }
064997fb
FG
829}
830
831fn scope_for(
832 scopes: &ExprScopes,
833 source_map: &BodySourceMap,
834 node: InFile<&SyntaxNode>,
835) -> Option<ScopeId> {
836 node.value
837 .ancestors()
838 .filter_map(ast::Expr::cast)
839 .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
840 .find_map(|it| scopes.scope_for(it))
841}
842
843fn scope_for_offset(
844 db: &dyn HirDatabase,
845 scopes: &ExprScopes,
846 source_map: &BodySourceMap,
847 from_file: HirFileId,
848 offset: TextSize,
849) -> Option<ScopeId> {
850 scopes
851 .scope_by_expr()
852 .iter()
853 .filter_map(|(id, scope)| {
854 let InFile { file_id, value } = source_map.expr_syntax(*id).ok()?;
855 if from_file == file_id {
856 return Some((value.text_range(), scope));
857 }
858
859 // FIXME handle attribute expansion
860 let source = iter::successors(file_id.call_node(db.upcast()), |it| {
861 it.file_id.call_node(db.upcast())
862 })
863 .find(|it| it.file_id == from_file)
864 .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?;
865 Some((source.value.text_range(), scope))
866 })
867 .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end())
868 // find containing scope
869 .min_by_key(|(expr_range, _scope)| expr_range.len())
870 .map(|(expr_range, scope)| {
871 adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope)
872 })
873}
874
875// XXX: during completion, cursor might be outside of any particular
876// expression. Try to figure out the correct scope...
877fn adjust(
878 db: &dyn HirDatabase,
879 scopes: &ExprScopes,
880 source_map: &BodySourceMap,
881 expr_range: TextRange,
882 from_file: HirFileId,
883 offset: TextSize,
884) -> Option<ScopeId> {
885 let child_scopes = scopes
886 .scope_by_expr()
887 .iter()
888 .filter_map(|(id, scope)| {
889 let source = source_map.expr_syntax(*id).ok()?;
890 // FIXME: correctly handle macro expansion
891 if source.file_id != from_file {
892 return None;
893 }
894 let root = source.file_syntax(db.upcast());
895 let node = source.value.to_node(&root);
896 Some((node.syntax().text_range(), scope))
897 })
898 .filter(|&(range, _)| {
899 range.start() <= offset && expr_range.contains_range(range) && range != expr_range
900 });
901
902 child_scopes
903 .max_by(|&(r1, _), &(r2, _)| {
904 if r1.contains_range(r2) {
905 std::cmp::Ordering::Greater
906 } else if r2.contains_range(r1) {
907 std::cmp::Ordering::Less
908 } else {
909 r1.start().cmp(&r2.start())
910 }
911 })
912 .map(|(_ptr, scope)| *scope)
913}
914
915#[inline]
916pub(crate) fn resolve_hir_path(
917 db: &dyn HirDatabase,
918 resolver: &Resolver,
919 path: &Path,
920) -> Option<PathResolution> {
921 resolve_hir_path_(db, resolver, path, false)
922}
923
924#[inline]
925pub(crate) fn resolve_hir_path_as_macro(
926 db: &dyn HirDatabase,
927 resolver: &Resolver,
928 path: &Path,
929) -> Option<Macro> {
930 resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(Into::into)
931}
932
933fn resolve_hir_path_(
934 db: &dyn HirDatabase,
935 resolver: &Resolver,
936 path: &Path,
937 prefer_value_ns: bool,
938) -> Option<PathResolution> {
939 let types = || {
940 let (ty, unresolved) = match path.type_anchor() {
941 Some(type_ref) => {
942 let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
943 res.map(|ty_ns| (ty_ns, path.segments().first()))
944 }
945 None => {
946 let (ty, remaining) =
947 resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
948 match remaining {
949 Some(remaining) if remaining > 1 => {
950 if remaining + 1 == path.segments().len() {
951 Some((ty, path.segments().last()))
952 } else {
953 None
954 }
955 }
956 _ => Some((ty, path.segments().get(1))),
957 }
958 }
959 }?;
960
961 // If we are in a TypeNs for a Trait, and we have an unresolved name, try to resolve it as a type
962 // within the trait's associated types.
963 if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) {
964 if let Some(type_alias_id) =
965 db.trait_data(trait_id).associated_type_by_name(unresolved.name)
966 {
967 return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into()));
968 }
969 }
970
971 let res = match ty {
972 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
973 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
974 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
975 PathResolution::Def(Adt::from(it).into())
976 }
977 TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
978 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
979 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
980 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
981 };
982 match unresolved {
983 Some(unresolved) => resolver
984 .generic_def()
985 .and_then(|def| {
986 hir_ty::associated_type_shorthand_candidates(
987 db,
988 def,
989 res.in_type_ns()?,
9c376795 990 |name, id| (name == unresolved.name).then_some(id),
064997fb
FG
991 )
992 })
993 .map(TypeAlias::from)
994 .map(Into::into)
995 .map(PathResolution::Def),
996 None => Some(res),
997 }
998 };
999
1000 let body_owner = resolver.body_owner();
1001 let values = || {
1002 resolver.resolve_path_in_value_ns_fully(db.upcast(), path.mod_path()).and_then(|val| {
1003 let res = match val {
1004 ValueNs::LocalBinding(pat_id) => {
1005 let var = Local { parent: body_owner?, pat_id };
1006 PathResolution::Local(var)
1007 }
1008 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
1009 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
1010 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
1011 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
1012 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
1013 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
1014 ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
1015 };
1016 Some(res)
1017 })
1018 };
1019
1020 let items = || {
1021 resolver
1022 .resolve_module_path_in_items(db.upcast(), path.mod_path())
1023 .take_types()
1024 .map(|it| PathResolution::Def(it.into()))
1025 };
1026
1027 let macros = || {
1028 resolver
1029 .resolve_path_as_macro(db.upcast(), path.mod_path())
1030 .map(|def| PathResolution::Def(ModuleDef::Macro(def.into())))
1031 };
1032
1033 if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
1034 .or_else(items)
1035 .or_else(macros)
1036}
1037
1038/// Resolves a path where we know it is a qualifier of another path.
1039///
1040/// For example, if we have:
1041/// ```
1042/// mod my {
1043/// pub mod foo {
1044/// struct Bar;
1045/// }
1046///
1047/// pub fn foo() {}
1048/// }
1049/// ```
1050/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
1051fn resolve_hir_path_qualifier(
1052 db: &dyn HirDatabase,
1053 resolver: &Resolver,
1054 path: &Path,
1055) -> Option<PathResolution> {
1056 resolver
1057 .resolve_path_in_type_ns_fully(db.upcast(), path.mod_path())
1058 .map(|ty| match ty {
1059 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
1060 TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
1061 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
1062 PathResolution::Def(Adt::from(it).into())
1063 }
1064 TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
1065 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
1066 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
1067 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
1068 })
1069 .or_else(|| {
1070 resolver
1071 .resolve_module_path_in_items(db.upcast(), path.mod_path())
1072 .take_types()
1073 .map(|it| PathResolution::Def(it.into()))
1074 })
1075}