aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs2
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs2
-rw-r--r--crates/ra_hir_expand/src/db.rs21
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs62
-rw-r--r--crates/ra_hir_expand/src/lib.rs31
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_expand/src/test_db.rs24
9 files changed, 105 insertions, 52 deletions
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index e5c9f3e99..6da0e2a16 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -3,6 +3,7 @@ edition = "2018"
3name = "ra_hir_expand" 3name = "ra_hir_expand"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index f4d31526a..8bfe1b4ba 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -73,7 +73,7 @@ impl AstIdMap {
73 // change parent's id. This means that, say, adding a new function to a 73 // change parent's id. This means that, say, adding a new function to a
74 // trait does not change ids of top-level items, which helps caching. 74 // trait does not change ids of top-level items, which helps caching.
75 bfs(node, |it| { 75 bfs(node, |it| {
76 if let Some(module_item) = ast::ModuleItem::cast(it) { 76 if let Some(module_item) = ast::Item::cast(it) {
77 res.alloc(module_item.syntax()); 77 res.alloc(module_item.syntax());
78 } 78 }
79 }); 79 });
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 26b667b55..69fa907cb 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -4,7 +4,7 @@ use log::debug;
4 4
5use ra_parser::FragmentKind; 5use ra_parser::FragmentKind;
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner}, 7 ast::{self, AstNode, GenericParamsOwner, ModuleItemOwner, NameOwner},
8 match_ast, 8 match_ast,
9}; 9};
10 10
@@ -72,9 +72,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
72 let node = item.syntax(); 72 let node = item.syntax();
73 let (name, params) = match_ast! { 73 let (name, params) = match_ast! {
74 match node { 74 match node {
75 ast::StructDef(it) => (it.name(), it.type_param_list()), 75 ast::Struct(it) => (it.name(), it.generic_param_list()),
76 ast::EnumDef(it) => (it.name(), it.type_param_list()), 76 ast::Enum(it) => (it.name(), it.generic_param_list()),
77 ast::UnionDef(it) => (it.name(), it.type_param_list()), 77 ast::Union(it) => (it.name(), it.generic_param_list()),
78 _ => { 78 _ => {
79 debug!("unexpected node is {:?}", node); 79 debug!("unexpected node is {:?}", node);
80 return Err(mbe::ExpandError::ConversionError) 80 return Err(mbe::ExpandError::ConversionError)
@@ -161,7 +161,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
161 // XXX 161 // XXX
162 // All crates except core itself should have a dependency on core, 162 // All crates except core itself should have a dependency on core,
163 // We detect `core` by seeing whether it doesn't have such a dependency. 163 // We detect `core` by seeing whether it doesn't have such a dependency.
164 let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { 164 let tt = if cg[krate].dependencies.iter().any(|dep| &*dep.name == "core") {
165 quote! { core } 165 quote! { core }
166 } else { 166 } else {
167 quote! { crate } 167 quote! { crate }
@@ -276,7 +276,7 @@ mod tests {
276 let file_id = file_pos.file_id; 276 let file_id = file_pos.file_id;
277 let parsed = db.parse(file_id); 277 let parsed = db.parse(file_id);
278 let items: Vec<_> = 278 let items: Vec<_> =
279 parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); 279 parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
280 280
281 let ast_id_map = db.ast_id_map(file_id.into()); 281 let ast_id_map = db.ast_id_map(file_id.into());
282 282
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 626f9efd0..9f50569dc 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -272,7 +272,7 @@ fn format_args_expand(
272fn unquote_str(lit: &tt::Literal) -> Option<String> { 272fn unquote_str(lit: &tt::Literal) -> Option<String> {
273 let lit = ast::make::tokens::literal(&lit.to_string()); 273 let lit = ast::make::tokens::literal(&lit.to_string());
274 let token = ast::String::cast(lit)?; 274 let token = ast::String::cast(lit)?;
275 token.value() 275 token.value().map(|it| it.into_owned())
276} 276}
277 277
278fn concat_expand( 278fn concat_expand(
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index bf30d7151..41df66696 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,7 +6,7 @@ use mbe::{ExpandResult, MacroRules};
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode}; 9use ra_syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
@@ -72,6 +72,8 @@ pub trait AstDatabase: SourceDatabase {
72 72
73 #[salsa::interned] 73 #[salsa::interned]
74 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId; 74 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
75 fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
76 #[salsa::transparent]
75 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; 77 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
76 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; 78 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
77 fn parse_macro(&self, macro_file: MacroFile) 79 fn parse_macro(&self, macro_file: MacroFile)
@@ -148,10 +150,7 @@ pub(crate) fn macro_def(
148 } 150 }
149} 151}
150 152
151pub(crate) fn macro_arg( 153pub(crate) fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
152 db: &dyn AstDatabase,
153 id: MacroCallId,
154) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
155 let id = match id { 154 let id = match id {
156 MacroCallId::LazyMacro(id) => id, 155 MacroCallId::LazyMacro(id) => id,
157 MacroCallId::EagerMacro(_id) => { 156 MacroCallId::EagerMacro(_id) => {
@@ -161,7 +160,15 @@ pub(crate) fn macro_arg(
161 }; 160 };
162 let loc = db.lookup_intern_macro(id); 161 let loc = db.lookup_intern_macro(id);
163 let arg = loc.kind.arg(db)?; 162 let arg = loc.kind.arg(db)?;
164 let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?; 163 Some(arg.green().clone())
164}
165
166pub(crate) fn macro_arg(
167 db: &dyn AstDatabase,
168 id: MacroCallId,
169) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
170 let arg = db.macro_arg_text(id)?;
171 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg))?;
165 Some(Arc::new((tt, tmap))) 172 Some(Arc::new((tt, tmap)))
166} 173}
167 174
@@ -379,7 +386,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
379 MATCH_EXPR => FragmentKind::Expr, 386 MATCH_EXPR => FragmentKind::Expr,
380 MATCH_ARM => FragmentKind::Expr, 387 MATCH_ARM => FragmentKind::Expr,
381 MATCH_GUARD => FragmentKind::Expr, 388 MATCH_GUARD => FragmentKind::Expr,
382 RECORD_FIELD => FragmentKind::Expr, 389 RECORD_EXPR_FIELD => FragmentKind::Expr,
383 CALL_EXPR => FragmentKind::Expr, 390 CALL_EXPR => FragmentKind::Expr,
384 INDEX_EXPR => FragmentKind::Expr, 391 INDEX_EXPR => FragmentKind::Expr,
385 METHOD_CALL_EXPR => FragmentKind::Expr, 392 METHOD_CALL_EXPR => FragmentKind::Expr,
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 99209c6e8..84ba97b14 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -24,11 +24,14 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> InFile<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn as_any(&self) -> &(dyn Any + Send + 'static); 26 fn as_any(&self) -> &(dyn Any + Send + 'static);
27 fn is_experimental(&self) -> bool {
28 false
29 }
27} 30}
28 31
29pub trait AstDiagnostic { 32pub trait AstDiagnostic {
30 type AST; 33 type AST;
31 fn ast(&self, db: &impl AstDatabase) -> Self::AST; 34 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
32} 35}
33 36
34impl dyn Diagnostic { 37impl dyn Diagnostic {
@@ -44,16 +47,48 @@ impl dyn Diagnostic {
44 47
45pub struct DiagnosticSink<'a> { 48pub struct DiagnosticSink<'a> {
46 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, 49 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
50 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
47 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>, 51 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
48} 52}
49 53
50impl<'a> DiagnosticSink<'a> { 54impl<'a> DiagnosticSink<'a> {
51 /// FIXME: split `new` and `on` into a separate builder type 55 pub fn push(&mut self, d: impl Diagnostic) {
52 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { 56 let d: &dyn Diagnostic = &d;
53 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } 57 self._push(d);
58 }
59
60 fn _push(&mut self, d: &dyn Diagnostic) {
61 for filter in &mut self.filters {
62 if !filter(d) {
63 return;
64 }
65 }
66 for cb in &mut self.callbacks {
67 match cb(d) {
68 Ok(()) => return,
69 Err(()) => (),
70 }
71 }
72 (self.default_callback)(d)
54 } 73 }
74}
55 75
56 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> { 76pub struct DiagnosticSinkBuilder<'a> {
77 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
78 filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>,
79}
80
81impl<'a> DiagnosticSinkBuilder<'a> {
82 pub fn new() -> Self {
83 Self { callbacks: Vec::new(), filters: Vec::new() }
84 }
85
86 pub fn filter<F: FnMut(&dyn Diagnostic) -> bool + 'a>(mut self, cb: F) -> Self {
87 self.filters.push(Box::new(cb));
88 self
89 }
90
91 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self {
57 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { 92 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
58 Some(d) => { 93 Some(d) => {
59 cb(d); 94 cb(d);
@@ -65,18 +100,11 @@ impl<'a> DiagnosticSink<'a> {
65 self 100 self
66 } 101 }
67 102
68 pub fn push(&mut self, d: impl Diagnostic) { 103 pub fn build<F: FnMut(&dyn Diagnostic) + 'a>(self, default_callback: F) -> DiagnosticSink<'a> {
69 let d: &dyn Diagnostic = &d; 104 DiagnosticSink {
70 self._push(d); 105 callbacks: self.callbacks,
71 } 106 filters: self.filters,
72 107 default_callback: Box::new(default_callback),
73 fn _push(&mut self, d: &dyn Diagnostic) {
74 for cb in self.callbacks.iter_mut() {
75 match cb(d) {
76 Ok(()) => return,
77 Err(()) => (),
78 }
79 } 108 }
80 (self.default_callback)(d)
81 } 109 }
82} 110}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 5eac2605b..2e8d63691 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -88,6 +88,25 @@ impl HirFileId {
88 } 88 }
89 } 89 }
90 90
91 pub fn expansion_level(self, db: &dyn db::AstDatabase) -> u32 {
92 let mut level = 0;
93 let mut curr = self;
94 while let HirFileIdRepr::MacroFile(macro_file) = curr.0 {
95 level += 1;
96 curr = match macro_file.macro_call_id {
97 MacroCallId::LazyMacro(id) => {
98 let loc = db.lookup_intern_macro(id);
99 loc.kind.file_id()
100 }
101 MacroCallId::EagerMacro(id) => {
102 let loc = db.lookup_intern_eager_expansion(id);
103 loc.file_id
104 }
105 };
106 }
107 level
108 }
109
91 /// If this is a macro call, returns the syntax node of the call. 110 /// If this is a macro call, returns the syntax node of the call.
92 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { 111 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
93 match self.0 { 112 match self.0 {
@@ -140,7 +159,7 @@ impl HirFileId {
140 } 159 }
141 160
142 /// Indicate it is macro file generated for builtin derive 161 /// Indicate it is macro file generated for builtin derive
143 pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::ModuleItem>> { 162 pub fn is_builtin_derive(&self, db: &dyn db::AstDatabase) -> Option<InFile<ast::Item>> {
144 match self.0 { 163 match self.0 {
145 HirFileIdRepr::FileId(_) => None, 164 HirFileIdRepr::FileId(_) => None,
146 HirFileIdRepr::MacroFile(macro_file) => { 165 HirFileIdRepr::MacroFile(macro_file) => {
@@ -155,7 +174,7 @@ impl HirFileId {
155 MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), 174 MacroDefKind::BuiltInDerive(_) => loc.kind.node(db),
156 _ => return None, 175 _ => return None,
157 }; 176 };
158 Some(item.with_value(ast::ModuleItem::cast(item.value.clone())?)) 177 Some(item.with_value(ast::Item::cast(item.value.clone())?))
159 } 178 }
160 } 179 }
161 } 180 }
@@ -239,18 +258,18 @@ pub struct MacroCallLoc {
239#[derive(Debug, Clone, PartialEq, Eq, Hash)] 258#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub enum MacroCallKind { 259pub enum MacroCallKind {
241 FnLike(AstId<ast::MacroCall>), 260 FnLike(AstId<ast::MacroCall>),
242 Attr(AstId<ast::ModuleItem>, String), 261 Attr(AstId<ast::Item>, String),
243} 262}
244 263
245impl MacroCallKind { 264impl MacroCallKind {
246 pub fn file_id(&self) -> HirFileId { 265 fn file_id(&self) -> HirFileId {
247 match self { 266 match self {
248 MacroCallKind::FnLike(ast_id) => ast_id.file_id, 267 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
249 MacroCallKind::Attr(ast_id, _) => ast_id.file_id, 268 MacroCallKind::Attr(ast_id, _) => ast_id.file_id,
250 } 269 }
251 } 270 }
252 271
253 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { 272 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
254 match self { 273 match self {
255 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), 274 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
256 MacroCallKind::Attr(ast_id, _) => { 275 MacroCallKind::Attr(ast_id, _) => {
@@ -259,7 +278,7 @@ impl MacroCallKind {
259 } 278 }
260 } 279 }
261 280
262 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 281 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
263 match self { 282 match self {
264 MacroCallKind::FnLike(ast_id) => { 283 MacroCallKind::FnLike(ast_id) => {
265 Some(ast_id.to_node(db).token_tree()?.syntax().clone()) 284 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 1b0303685..969a2e5b8 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -117,7 +117,7 @@ impl AsName for ast::FieldKind {
117 117
118impl AsName for ra_db::Dependency { 118impl AsName for ra_db::Dependency {
119 fn as_name(&self) -> Name { 119 fn as_name(&self) -> Name {
120 Name::new_text(self.name.clone()) 120 Name::new_text(SmolStr::new(&*self.name))
121 } 121 }
122} 122}
123 123
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index 09fc18c36..332fa556f 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -1,7 +1,7 @@
1//! Database used for testing `hir_expand`. 1//! Database used for testing `hir_expand`.
2 2
3use std::{ 3use std::{
4 panic, 4 fmt, panic,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
@@ -13,25 +13,23 @@ use rustc_hash::FxHashSet;
13 ra_db::SourceDatabaseStorage, 13 ra_db::SourceDatabaseStorage,
14 crate::db::AstDatabaseStorage 14 crate::db::AstDatabaseStorage
15)] 15)]
16#[derive(Debug, Default)] 16#[derive(Default)]
17pub struct TestDB { 17pub struct TestDB {
18 runtime: salsa::Runtime<TestDB>, 18 storage: salsa::Storage<TestDB>,
19 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, 19 events: Mutex<Option<Vec<salsa::Event>>>,
20} 20}
21 21
22impl salsa::Database for TestDB { 22impl fmt::Debug for TestDB {
23 fn salsa_runtime(&self) -> &salsa::Runtime<Self> { 23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 &self.runtime 24 f.debug_struct("TestDB").finish()
25 }
26
27 fn salsa_runtime_mut(&mut self) -> &mut salsa::Runtime<Self> {
28 &mut self.runtime
29 } 25 }
26}
30 27
31 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { 28impl salsa::Database for TestDB {
29 fn salsa_event(&self, event: salsa::Event) {
32 let mut events = self.events.lock().unwrap(); 30 let mut events = self.events.lock().unwrap();
33 if let Some(events) = &mut *events { 31 if let Some(events) = &mut *events {
34 events.push(event()); 32 events.push(event);
35 } 33 }
36 } 34 }
37} 35}