aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/semantics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/semantics.rs')
-rw-r--r--crates/ra_hir/src/semantics.rs138
1 files changed, 124 insertions, 14 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 307b336f2..36b688ccb 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -8,7 +8,7 @@ use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, FunctionId, TraitId, VariantId, 9 AsMacroCall, FunctionId, TraitId, VariantId,
10}; 10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
13use itertools::Itertools; 13use itertools::Itertools;
14use ra_db::{FileId, FileRange}; 14use ra_db::{FileId, FileRange};
@@ -24,8 +24,9 @@ use crate::{
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, 27 AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, 28 Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
29 VariantDef,
29}; 30};
30use resolver::TypeNs; 31use resolver::TypeNs;
31 32
@@ -109,13 +110,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
109 self.imp.parse(file_id) 110 self.imp.parse(file_id)
110 } 111 }
111 112
112 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
113 let file_id = d.source().file_id;
114 let root = self.db.parse_or_expand(file_id).unwrap();
115 self.imp.cache(root, file_id);
116 d.ast(self.db.upcast())
117 }
118
119 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 113 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
120 self.imp.expand(macro_call) 114 self.imp.expand(macro_call)
121 } 115 }
@@ -145,8 +139,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
145 self.imp.original_range(node) 139 self.imp.original_range(node)
146 } 140 }
147 141
148 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { 142 pub fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
149 self.imp.diagnostics_range(diagnostics) 143 self.imp.diagnostics_display_range(diagnostics)
150 } 144 }
151 145
152 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { 146 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
@@ -228,6 +222,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
228 self.imp.resolve_path(path) 222 self.imp.resolve_path(path)
229 } 223 }
230 224
225 pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
226 self.imp.resolve_extern_crate(extern_crate)
227 }
228
231 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { 229 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
232 self.imp.resolve_variant(record_lit).map(VariantDef::from) 230 self.imp.resolve_variant(record_lit).map(VariantDef::from)
233 } 231 }
@@ -275,6 +273,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
275 pub fn assert_contains_node(&self, node: &SyntaxNode) { 273 pub fn assert_contains_node(&self, node: &SyntaxNode) {
276 self.imp.assert_contains_node(node) 274 self.imp.assert_contains_node(node)
277 } 275 }
276
277 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
278 self.imp.is_unsafe_method_call(method_call_expr)
279 }
280
281 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
282 self.imp.is_unsafe_ref_expr(ref_expr)
283 }
284
285 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
286 self.imp.is_unsafe_ident_pat(ident_pat)
287 }
278} 288}
279 289
280impl<'db> SemanticsImpl<'db> { 290impl<'db> SemanticsImpl<'db> {
@@ -372,10 +382,11 @@ impl<'db> SemanticsImpl<'db> {
372 original_range(self.db, node.as_ref()) 382 original_range(self.db, node.as_ref())
373 } 383 }
374 384
375 fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { 385 fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
376 let src = diagnostics.source(); 386 let src = diagnostics.display_source();
377 let root = self.db.parse_or_expand(src.file_id).unwrap(); 387 let root = self.db.parse_or_expand(src.file_id).unwrap();
378 let node = src.value.to_node(&root); 388 let node = src.value.to_node(&root);
389 self.cache(root, src.file_id);
379 original_range(self.db, src.with_value(&node)) 390 original_range(self.db, src.with_value(&node))
380 } 391 }
381 392
@@ -443,6 +454,17 @@ impl<'db> SemanticsImpl<'db> {
443 self.analyze(path.syntax()).resolve_path(self.db, path) 454 self.analyze(path.syntax()).resolve_path(self.db, path)
444 } 455 }
445 456
457 fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
458 let krate = self.scope(extern_crate.syntax()).krate()?;
459 krate.dependencies(self.db).into_iter().find_map(|dep| {
460 if dep.name == extern_crate.name_ref()?.as_name() {
461 Some(dep.krate)
462 } else {
463 None
464 }
465 })
466 }
467
446 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { 468 fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
447 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) 469 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
448 } 470 }
@@ -559,6 +581,90 @@ impl<'db> SemanticsImpl<'db> {
559 }); 581 });
560 InFile::new(file_id, node) 582 InFile::new(file_id, node)
561 } 583 }
584
585 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
586 method_call_expr
587 .expr()
588 .and_then(|expr| {
589 let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
590 field_expr
591 } else {
592 return None;
593 };
594 let ty = self.type_of_expr(&field_expr.expr()?)?;
595 if !ty.is_packed(self.db) {
596 return None;
597 }
598
599 let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
600 let is_unsafe = func.has_self_param(self.db)
601 && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
602 Some(is_unsafe)
603 })
604 .unwrap_or(false)
605 }
606
607 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
608 ref_expr
609 .expr()
610 .and_then(|expr| {
611 let field_expr = match expr {
612 ast::Expr::FieldExpr(field_expr) => field_expr,
613 _ => return None,
614 };
615 let expr = field_expr.expr()?;
616 self.type_of_expr(&expr)
617 })
618 // Binding a reference to a packed type is possibly unsafe.
619 .map(|ty| ty.is_packed(self.db))
620 .unwrap_or(false)
621
622 // FIXME This needs layout computation to be correct. It will highlight
623 // more than it should with the current implementation.
624 }
625
626 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
627 if !ident_pat.ref_token().is_some() {
628 return false;
629 }
630
631 ident_pat
632 .syntax()
633 .parent()
634 .and_then(|parent| {
635 // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
636 // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
637 // so this tries to lookup the `IdentPat` anywhere along that structure to the
638 // `RecordPat` so we can get the containing type.
639 let record_pat = ast::RecordPatField::cast(parent.clone())
640 .and_then(|record_pat| record_pat.syntax().parent())
641 .or_else(|| Some(parent.clone()))
642 .and_then(|parent| {
643 ast::RecordPatFieldList::cast(parent)?
644 .syntax()
645 .parent()
646 .and_then(ast::RecordPat::cast)
647 });
648
649 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
650 // this is initialized from a `FieldExpr`.
651 if let Some(record_pat) = record_pat {
652 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
653 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
654 let field_expr = match let_stmt.initializer()? {
655 ast::Expr::FieldExpr(field_expr) => field_expr,
656 _ => return None,
657 };
658
659 self.type_of_expr(&field_expr.expr()?)
660 } else {
661 None
662 }
663 })
664 // Binding a reference to a packed type is possibly unsafe.
665 .map(|ty| ty.is_packed(self.db))
666 .unwrap_or(false)
667 }
562} 668}
563 669
564pub trait ToDef: AstNode + Clone { 670pub trait ToDef: AstNode + Clone {
@@ -612,6 +718,10 @@ impl<'a> SemanticsScope<'a> {
612 Some(Module { id: self.resolver.module()? }) 718 Some(Module { id: self.resolver.module()? })
613 } 719 }
614 720
721 pub fn krate(&self) -> Option<Crate> {
722 Some(Crate { id: self.resolver.krate()? })
723 }
724
615 /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type 725 /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
616 // FIXME: rename to visible_traits to not repeat scope? 726 // FIXME: rename to visible_traits to not repeat scope?
617 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { 727 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {