diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 138 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 7 |
5 files changed, 149 insertions, 24 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 27cdabea0..0007d7fa8 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -4,6 +4,7 @@ use std::{iter, sync::Arc}; | |||
4 | use arrayvec::ArrayVec; | 4 | use arrayvec::ArrayVec; |
5 | use either::Either; | 5 | use either::Either; |
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | adt::ReprKind, | ||
7 | adt::StructKind, | 8 | adt::StructKind, |
8 | adt::VariantData, | 9 | adt::VariantData, |
9 | builtin_type::BuiltinType, | 10 | builtin_type::BuiltinType, |
@@ -83,9 +84,9 @@ impl Crate { | |||
83 | .collect() | 84 | .collect() |
84 | } | 85 | } |
85 | 86 | ||
86 | pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> { | 87 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { |
87 | let module_id = db.crate_def_map(self.id).root; | 88 | let module_id = db.crate_def_map(self.id).root; |
88 | Some(Module::new(self, module_id)) | 89 | Module::new(self, module_id) |
89 | } | 90 | } |
90 | 91 | ||
91 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { | 92 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { |
@@ -431,6 +432,10 @@ impl Struct { | |||
431 | Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) | 432 | Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) |
432 | } | 433 | } |
433 | 434 | ||
435 | pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { | ||
436 | db.struct_data(self.id).repr.clone() | ||
437 | } | ||
438 | |||
434 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | 439 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { |
435 | db.struct_data(self.id).variant_data.clone() | 440 | db.struct_data(self.id).variant_data.clone() |
436 | } | 441 | } |
@@ -1253,6 +1258,19 @@ impl Type { | |||
1253 | ) | 1258 | ) |
1254 | } | 1259 | } |
1255 | 1260 | ||
1261 | pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { | ||
1262 | let adt_id = match self.ty.value { | ||
1263 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id, | ||
1264 | _ => return false, | ||
1265 | }; | ||
1266 | |||
1267 | let adt = adt_id.into(); | ||
1268 | match adt { | ||
1269 | Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), | ||
1270 | _ => false, | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1256 | pub fn is_raw_ptr(&self) -> bool { | 1274 | pub fn is_raw_ptr(&self) -> bool { |
1257 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) | 1275 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) |
1258 | } | 1276 | } |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 266b513dc..363164b9b 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | pub use hir_def::diagnostics::UnresolvedModule; | 2 | pub use hir_def::diagnostics::UnresolvedModule; |
3 | pub use hir_expand::diagnostics::{ | 3 | pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder}; |
4 | AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, | ||
5 | }; | ||
6 | pub use hir_ty::diagnostics::{ | 4 | pub use hir_ty::diagnostics::{ |
7 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, | 5 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, |
8 | }; | 6 | }; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 31f3241c9..34b02c536 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -49,7 +49,7 @@ pub use hir_def::{ | |||
49 | docs::Documentation, | 49 | docs::Documentation, |
50 | nameres::ModuleSource, | 50 | nameres::ModuleSource, |
51 | path::{ModPath, Path, PathKind}, | 51 | path::{ModPath, Path, PathKind}, |
52 | type_ref::Mutability, | 52 | type_ref::{Mutability, TypeRef}, |
53 | }; | 53 | }; |
54 | pub use hir_expand::{ | 54 | pub use hir_expand::{ |
55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, | 55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, |
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 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{FileId, FileRange}; | 14 | use 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 | }; |
30 | use resolver::TypeNs; | 31 | use 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 | ||
280 | impl<'db> SemanticsImpl<'db> { | 290 | impl<'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 | ||
564 | pub trait ToDef: AstNode + Clone { | 670 | pub 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> { |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index d0cb62ef0..d3d62debf 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -265,8 +265,7 @@ impl SourceAnalyzer { | |||
265 | } | 265 | } |
266 | 266 | ||
267 | // This must be a normal source file rather than macro file. | 267 | // This must be a normal source file rather than macro file. |
268 | let hir_path = | 268 | let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; |
269 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | ||
270 | 269 | ||
271 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we | 270 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we |
272 | // trying to resolve foo::bar. | 271 | // trying to resolve foo::bar. |
@@ -451,7 +450,7 @@ fn adjust( | |||
451 | pub(crate) fn resolve_hir_path( | 450 | pub(crate) fn resolve_hir_path( |
452 | db: &dyn HirDatabase, | 451 | db: &dyn HirDatabase, |
453 | resolver: &Resolver, | 452 | resolver: &Resolver, |
454 | path: &crate::Path, | 453 | path: &Path, |
455 | ) -> Option<PathResolution> { | 454 | ) -> Option<PathResolution> { |
456 | let types = | 455 | let types = |
457 | resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { | 456 | resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { |
@@ -512,7 +511,7 @@ pub(crate) fn resolve_hir_path( | |||
512 | pub(crate) fn resolve_hir_path_qualifier( | 511 | pub(crate) fn resolve_hir_path_qualifier( |
513 | db: &dyn HirDatabase, | 512 | db: &dyn HirDatabase, |
514 | resolver: &Resolver, | 513 | resolver: &Resolver, |
515 | path: &crate::Path, | 514 | path: &Path, |
516 | ) -> Option<PathResolution> { | 515 | ) -> Option<PathResolution> { |
517 | let items = resolver | 516 | let items = resolver |
518 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) | 517 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) |