Skip to content

Commit 25ae0e9

Browse files
committed
WIP
1 parent dda3791 commit 25ae0e9

File tree

4 files changed

+84
-43
lines changed

4 files changed

+84
-43
lines changed

crates/ra_hir/src/semantics.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{cell::RefCell, iter::successors};
1+
use std::{cell::RefCell, fmt, iter::successors};
22

33
use ra_db::{FileId, FileRange};
44
use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
@@ -16,6 +16,12 @@ pub struct Semantics<'a, DB> {
1616
cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
1717
}
1818

19+
impl<DB> fmt::Debug for Semantics<'_, DB> {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
write!(f, "Semantics {{ ... }}")
22+
}
23+
}
24+
1925
impl<DB: HirDatabase> Semantics<'_, DB> {
2026
pub fn new(db: &DB) -> Semantics<DB> {
2127
let sb = RefCell::new(SourceBinder::new(db));
@@ -186,14 +192,34 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
186192
let prev = cache.insert(root_node, file_id);
187193
assert!(prev.is_none());
188194
}
189-
fn lookup(&self, root_node: &SyntaxNode) -> HirFileId {
195+
196+
pub fn assert_contains_node(&self, node: &SyntaxNode) {
197+
self.find_file(node.clone());
198+
}
199+
200+
fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
190201
let cache = self.cache.borrow();
191-
cache[root_node]
202+
cache.get(root_node).copied()
192203
}
193204

194205
fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
195206
let root_node = find_root(&node);
196-
let file_id = self.lookup(&root_node);
207+
let file_id = self.lookup(&root_node).unwrap_or_else(|| {
208+
panic!(
209+
"\n\nFailed to lookup {:?} in this Semantics.\n\
210+
Make sure to use only query nodes, derived from this instance of Semantics.\n\
211+
root node: {:?}\n\
212+
known nodes: {}\n\n",
213+
node,
214+
root_node,
215+
self.cache
216+
.borrow()
217+
.keys()
218+
.map(|it| format!("{:?}", it))
219+
.collect::<Vec<_>>()
220+
.join(", ")
221+
)
222+
});
197223
InFile::new(file_id, node)
198224
}
199225
}

crates/ra_ide/src/completion.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ mod complete_postfix;
1717
mod complete_macro_in_item_position;
1818
mod complete_trait_impl;
1919

20-
use ra_db::SourceDatabase;
2120
use ra_ide_db::RootDatabase;
2221

2322
#[cfg(test)]
@@ -57,8 +56,7 @@ pub use crate::completion::completion_item::{
5756
/// identifier prefix/fuzzy match should be done higher in the stack, together
5857
/// with ordering of completions (currently this is done by the client).
5958
pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option<Completions> {
60-
let original_parse = db.parse(position.file_id);
61-
let ctx = CompletionContext::new(db, &original_parse, position)?;
59+
let ctx = CompletionContext::new(db, position)?;
6260

6361
let mut acc = Completions::default();
6462

crates/ra_ide/src/completion/complete_trait_impl.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,35 +64,38 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
6464
if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
6565
match trigger.kind() {
6666
SyntaxKind::FN_DEF => {
67-
for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
68-
.iter()
69-
.filter_map(|item| match item {
70-
hir::AssocItem::Function(fn_item) => Some(fn_item),
71-
_ => None,
67+
for missing_fn in
68+
get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
69+
match item {
70+
hir::AssocItem::Function(fn_item) => Some(fn_item),
71+
_ => None,
72+
}
7273
})
7374
{
7475
add_function_impl(&trigger, acc, ctx, &missing_fn);
7576
}
7677
}
7778

7879
SyntaxKind::TYPE_ALIAS_DEF => {
79-
for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
80-
.iter()
81-
.filter_map(|item| match item {
82-
hir::AssocItem::TypeAlias(type_item) => Some(type_item),
83-
_ => None,
80+
for missing_fn in
81+
get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
82+
match item {
83+
hir::AssocItem::TypeAlias(type_item) => Some(type_item),
84+
_ => None,
85+
}
8486
})
8587
{
8688
add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
8789
}
8890
}
8991

9092
SyntaxKind::CONST_DEF => {
91-
for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
92-
.iter()
93-
.filter_map(|item| match item {
94-
hir::AssocItem::Const(const_item) => Some(const_item),
95-
_ => None,
93+
for missing_fn in
94+
get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
95+
match item {
96+
hir::AssocItem::Const(const_item) => Some(const_item),
97+
_ => None,
98+
}
9699
})
97100
{
98101
add_const_impl(&trigger, acc, ctx, &missing_fn);

crates/ra_ide/src/completion/completion_context.rs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! FIXME: write short doc here
22
3+
use hir::Semantics;
4+
use ra_db::SourceDatabase;
35
use ra_ide_db::RootDatabase;
46
use ra_syntax::{
57
algo::{find_covering_element, find_node_at_offset},
6-
ast, AstNode, Parse, SourceFile,
8+
ast, AstNode, SourceFile,
79
SyntaxKind::*,
810
SyntaxNode, SyntaxToken, TextRange, TextUnit,
911
};
@@ -15,6 +17,7 @@ use crate::FilePosition;
1517
/// exactly is the cursor, syntax-wise.
1618
#[derive(Debug)]
1719
pub(crate) struct CompletionContext<'a> {
20+
pub(super) sema: Semantics<'a, RootDatabase>,
1821
pub(super) db: &'a RootDatabase,
1922
pub(super) analyzer: hir::SourceAnalyzer,
2023
pub(super) offset: TextUnit,
@@ -51,18 +54,30 @@ pub(crate) struct CompletionContext<'a> {
5154
impl<'a> CompletionContext<'a> {
5255
pub(super) fn new(
5356
db: &'a RootDatabase,
54-
original_parse: &'a Parse<ast::SourceFile>,
5557
position: FilePosition,
5658
) -> Option<CompletionContext<'a>> {
59+
let sema = Semantics::new(db);
60+
61+
let original_file = sema.file_syntax(position.file_id);
62+
63+
// Insert a fake ident to get a valid parse tree. We will use this file
64+
// to determine context, though the original_file will be used for
65+
// actual completion.
66+
let file_with_fake_ident = {
67+
let parse = db.parse(position.file_id);
68+
let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string());
69+
parse.reparse(&edit).tree()
70+
};
71+
5772
let mut sb = hir::SourceBinder::new(db);
58-
let module = sb.to_module_def(position.file_id);
59-
let token =
60-
original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?;
73+
let module = sema.to_module_def(position.file_id);
74+
let token = original_file.syntax().token_at_offset(position.offset).left_biased()?;
6175
let analyzer = sb.analyze(
6276
hir::InFile::new(position.file_id.into(), &token.parent()),
6377
Some(position.offset),
6478
);
6579
let mut ctx = CompletionContext {
80+
sema,
6681
db,
6782
analyzer,
6883
token,
@@ -87,7 +102,7 @@ impl<'a> CompletionContext<'a> {
87102
has_type_args: false,
88103
dot_receiver_is_ambiguous_float_literal: false,
89104
};
90-
ctx.fill(&original_parse, position.offset);
105+
ctx.fill(&original_file, file_with_fake_ident, position.offset);
91106
Some(ctx)
92107
}
93108

@@ -100,29 +115,29 @@ impl<'a> CompletionContext<'a> {
100115
}
101116
}
102117

103-
fn fill(&mut self, original_parse: &'a Parse<ast::SourceFile>, offset: TextUnit) {
104-
// Insert a fake ident to get a valid parse tree. We will use this file
105-
// to determine context, though the original_file will be used for
106-
// actual completion.
107-
let file = {
108-
let edit = AtomTextEdit::insert(offset, "intellijRulezz".to_string());
109-
original_parse.reparse(&edit).tree()
110-
};
111-
118+
fn fill(
119+
&mut self,
120+
original_file: &ast::SourceFile,
121+
file_with_fake_ident: ast::SourceFile,
122+
offset: TextUnit,
123+
) {
112124
// First, let's try to complete a reference to some declaration.
113-
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) {
125+
if let Some(name_ref) =
126+
find_node_at_offset::<ast::NameRef>(file_with_fake_ident.syntax(), offset)
127+
{
114128
// Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
115129
// See RFC#1685.
116130
if is_node::<ast::Param>(name_ref.syntax()) {
117131
self.is_param = true;
118132
return;
119133
}
120-
self.classify_name_ref(original_parse.tree(), name_ref);
134+
self.classify_name_ref(original_file, name_ref);
121135
}
122136

123137
// Otherwise, see if this is a declaration. We can use heuristics to
124138
// suggest declaration names, see `CompletionKind::Magic`.
125-
if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) {
139+
if let Some(name) = find_node_at_offset::<ast::Name>(file_with_fake_ident.syntax(), offset)
140+
{
126141
if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
127142
let parent = bind_pat.syntax().parent();
128143
if parent.clone().and_then(ast::MatchArm::cast).is_some()
@@ -136,13 +151,12 @@ impl<'a> CompletionContext<'a> {
136151
return;
137152
}
138153
if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
139-
self.record_lit_pat =
140-
find_node_at_offset(original_parse.tree().syntax(), self.offset);
154+
self.record_lit_pat = find_node_at_offset(original_file.syntax(), self.offset);
141155
}
142156
}
143157
}
144158

145-
fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
159+
fn classify_name_ref(&mut self, original_file: &SourceFile, name_ref: ast::NameRef) {
146160
self.name_ref_syntax =
147161
find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
148162
let name_range = name_ref.syntax().text_range();

0 commit comments

Comments
 (0)