aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/hygiene.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/hygiene.rs')
-rw-r--r--crates/hir_expand/src/hygiene.rs66
1 files changed, 66 insertions, 0 deletions
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
new file mode 100644
index 000000000..845e9cbc1
--- /dev/null
+++ b/crates/hir_expand/src/hygiene.rs
@@ -0,0 +1,66 @@
1//! This modules handles hygiene information.
2//!
3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
4//! this moment, this is horribly incomplete and handles only `$crate`.
5use base_db::CrateId;
6use either::Either;
7use syntax::ast;
8
9use crate::{
10 db::AstDatabase,
11 name::{AsName, Name},
12 HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
13};
14
15#[derive(Clone, Debug)]
16pub struct Hygiene {
17 // This is what `$crate` expands to
18 def_crate: Option<CrateId>,
19
20 // Indicate this is a local inner macro
21 local_inner: bool,
22}
23
24impl Hygiene {
25 pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
26 let (def_crate, local_inner) = match file_id.0 {
27 HirFileIdRepr::FileId(_) => (None, false),
28 HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
29 MacroCallId::LazyMacro(id) => {
30 let loc = db.lookup_intern_macro(id);
31 match loc.def.kind {
32 MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner),
33 MacroDefKind::BuiltIn(_) => (None, false),
34 MacroDefKind::BuiltInDerive(_) => (None, false),
35 MacroDefKind::BuiltInEager(_) => (None, false),
36 MacroDefKind::CustomDerive(_) => (None, false),
37 }
38 }
39 MacroCallId::EagerMacro(_id) => (None, false),
40 },
41 };
42 Hygiene { def_crate, local_inner }
43 }
44
45 pub fn new_unhygienic() -> Hygiene {
46 Hygiene { def_crate: None, local_inner: false }
47 }
48
49 // FIXME: this should just return name
50 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
51 if let Some(def_crate) = self.def_crate {
52 if name_ref.text() == "$crate" {
53 return Either::Right(def_crate);
54 }
55 }
56 Either::Left(name_ref.as_name())
57 }
58
59 pub fn local_inner_macros(&self) -> Option<CrateId> {
60 if self.local_inner {
61 self.def_crate
62 } else {
63 None
64 }
65 }
66}