mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-24 12:03:31 +00:00
reformat the world
This commit is contained in:
parent
5cb1d41a30
commit
12e3b4c70b
129 changed files with 727 additions and 2509 deletions
|
@ -80,10 +80,7 @@ impl RawMessage {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
msg: RawMessage,
|
msg: RawMessage,
|
||||||
}
|
}
|
||||||
let text = to_string(&JsonRpc {
|
let text = to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?;
|
||||||
jsonrpc: "2.0",
|
|
||||||
msg: self,
|
|
||||||
})?;
|
|
||||||
write_msg_text(w, &text)?;
|
write_msg_text(w, &text)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,11 +92,7 @@ impl RawRequest {
|
||||||
R: Request,
|
R: Request,
|
||||||
R::Params: serde::Serialize,
|
R::Params: serde::Serialize,
|
||||||
{
|
{
|
||||||
RawRequest {
|
RawRequest { id, method: R::METHOD.to_string(), params: to_value(params).unwrap() }
|
||||||
id,
|
|
||||||
method: R::METHOD.to_string(),
|
|
||||||
params: to_value(params).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn cast<R>(self) -> ::std::result::Result<(u64, R::Params), RawRequest>
|
pub fn cast<R>(self) -> ::std::result::Result<(u64, R::Params), RawRequest>
|
||||||
where
|
where
|
||||||
|
@ -121,23 +114,11 @@ impl RawResponse {
|
||||||
R: Request,
|
R: Request,
|
||||||
R::Result: serde::Serialize,
|
R::Result: serde::Serialize,
|
||||||
{
|
{
|
||||||
RawResponse {
|
RawResponse { id, result: Some(to_value(&result).unwrap()), error: None }
|
||||||
id,
|
|
||||||
result: Some(to_value(&result).unwrap()),
|
|
||||||
error: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn err(id: u64, code: i32, message: String) -> RawResponse {
|
pub fn err(id: u64, code: i32, message: String) -> RawResponse {
|
||||||
let error = RawResponseError {
|
let error = RawResponseError { code, message, data: None };
|
||||||
code,
|
RawResponse { id, result: None, error: Some(error) }
|
||||||
message,
|
|
||||||
data: None,
|
|
||||||
};
|
|
||||||
RawResponse {
|
|
||||||
id,
|
|
||||||
result: None,
|
|
||||||
error: Some(error),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,10 +128,7 @@ impl RawNotification {
|
||||||
N: Notification,
|
N: Notification,
|
||||||
N::Params: serde::Serialize,
|
N::Params: serde::Serialize,
|
||||||
{
|
{
|
||||||
RawNotification {
|
RawNotification { method: N::METHOD.to_string(), params: to_value(params).unwrap() }
|
||||||
method: N::METHOD.to_string(),
|
|
||||||
params: to_value(params).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn is<N>(&self) -> bool
|
pub fn is<N>(&self) -> bool
|
||||||
where
|
where
|
||||||
|
@ -187,9 +165,8 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> {
|
||||||
}
|
}
|
||||||
let mut parts = buf.splitn(2, ": ");
|
let mut parts = buf.splitn(2, ": ");
|
||||||
let header_name = parts.next().unwrap();
|
let header_name = parts.next().unwrap();
|
||||||
let header_value = parts
|
let header_value =
|
||||||
.next()
|
parts.next().ok_or_else(|| format_err!("malformed header: {:?}", buf))?;
|
||||||
.ok_or_else(|| format_err!("malformed header: {:?}", buf))?;
|
|
||||||
if header_name == "Content-Length" {
|
if header_name == "Content-Length" {
|
||||||
size = Some(header_value.parse::<usize>()?);
|
size = Some(header_value.parse::<usize>()?);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ pub fn stdio_transport() -> (Receiver<RawMessage>, Sender<RawMessage>, Threads)
|
||||||
let writer = thread::spawn(move || {
|
let writer = thread::spawn(move || {
|
||||||
let stdout = stdout();
|
let stdout = stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
writer_receiver
|
writer_receiver.into_iter().try_for_each(|it| it.write(&mut stdout))?;
|
||||||
.into_iter()
|
|
||||||
.try_for_each(|it| it.write(&mut stdout))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
let (reader_sender, reader_receiver) = bounded::<RawMessage>(16);
|
let (reader_sender, reader_receiver) = bounded::<RawMessage>(16);
|
||||||
|
|
|
@ -44,10 +44,7 @@ pub struct Arena<ID: ArenaId, T> {
|
||||||
|
|
||||||
impl<ID: ArenaId, T: fmt::Debug> fmt::Debug for Arena<ID, T> {
|
impl<ID: ArenaId, T: fmt::Debug> fmt::Debug for Arena<ID, T> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct("Arena")
|
fmt.debug_struct("Arena").field("len", &self.len()).field("data", &self.data).finish()
|
||||||
.field("len", &self.len())
|
|
||||||
.field("data", &self.data)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,19 +77,13 @@ impl<ID: ArenaId, T> Arena<ID, T> {
|
||||||
ID::from_raw(id)
|
ID::from_raw(id)
|
||||||
}
|
}
|
||||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ID, &'a T)> {
|
pub fn iter<'a>(&'a self) -> impl Iterator<Item = (ID, &'a T)> {
|
||||||
self.data
|
self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<ID: ArenaId, T> Default for Arena<ID, T> {
|
impl<ID: ArenaId, T> Default for Arena<ID, T> {
|
||||||
fn default() -> Arena<ID, T> {
|
fn default() -> Arena<ID, T> {
|
||||||
Arena {
|
Arena { data: Vec::new(), _ty: PhantomData }
|
||||||
data: Vec::new(),
|
|
||||||
_ty: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,9 +107,6 @@ impl<ID: ArenaId, T> FromIterator<T> for Arena<ID, T> {
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
{
|
{
|
||||||
Arena {
|
Arena { data: Vec::from_iter(iter), _ty: PhantomData }
|
||||||
data: Vec::from_iter(iter),
|
|
||||||
_ty: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,7 @@ impl<ID: ArenaId, T> ArenaMap<ID, T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> {
|
pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> {
|
||||||
self.v
|
self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_idx(id: ID) -> usize {
|
fn to_idx(id: ID) -> usize {
|
||||||
|
@ -66,9 +63,6 @@ impl<ID: ArenaId, T> std::ops::Index<ID> for ArenaMap<ID, T> {
|
||||||
|
|
||||||
impl<ID, T> Default for ArenaMap<ID, T> {
|
impl<ID, T> Default for ArenaMap<ID, T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
ArenaMap {
|
ArenaMap { v: Vec::new(), _ty: PhantomData }
|
||||||
v: Vec::new(),
|
|
||||||
_ty: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,8 @@ pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||||
|
|
||||||
// Insert `derive` after doc comments.
|
// Insert `derive` after doc comments.
|
||||||
fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
|
fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
|
||||||
let non_ws_child = nominal
|
let non_ws_child =
|
||||||
.syntax()
|
nominal.syntax().children().find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
|
||||||
.children()
|
|
||||||
.find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
|
|
||||||
Some(non_ws_child.range().start())
|
Some(non_ws_child.range().start())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,11 @@ pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||||
buf.push_str(" ");
|
buf.push_str(" ");
|
||||||
buf.push_str(name.text().as_str());
|
buf.push_str(name.text().as_str());
|
||||||
if let Some(type_params) = type_params {
|
if let Some(type_params) = type_params {
|
||||||
let lifetime_params = type_params
|
let lifetime_params =
|
||||||
.lifetime_params()
|
type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text());
|
||||||
.filter_map(|it| it.lifetime())
|
let type_params =
|
||||||
.map(|it| it.text());
|
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text());
|
||||||
let type_params = type_params
|
join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
|
||||||
.type_params()
|
|
||||||
.filter_map(|it| it.name())
|
|
||||||
.map(|it| it.text());
|
|
||||||
join(lifetime_params.chain(type_params))
|
|
||||||
.surround_with("<", ">")
|
|
||||||
.to_buf(&mut buf);
|
|
||||||
}
|
}
|
||||||
buf.push_str(" {\n");
|
buf.push_str(" {\n");
|
||||||
edit.set_cursor(start_offset + TextUnit::of_str(&buf));
|
edit.set_cursor(start_offset + TextUnit::of_str(&buf));
|
||||||
|
@ -47,11 +41,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_impl() {
|
fn test_add_impl() {
|
||||||
check_assist(
|
check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n");
|
||||||
add_impl,
|
|
||||||
"struct Foo {<|>}\n",
|
|
||||||
"struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
|
|
||||||
);
|
|
||||||
check_assist(
|
check_assist(
|
||||||
add_impl,
|
add_impl,
|
||||||
"struct Foo<T: Clone> {<|>}",
|
"struct Foo<T: Clone> {<|>}",
|
||||||
|
|
|
@ -69,12 +69,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
|
||||||
F: FnOnce(AssistCtx<DB>) -> T,
|
F: FnOnce(AssistCtx<DB>) -> T,
|
||||||
{
|
{
|
||||||
let source_file = &db.parse(frange.file_id);
|
let source_file = &db.parse(frange.file_id);
|
||||||
let ctx = AssistCtx {
|
let ctx = AssistCtx { db, frange, source_file, should_compute_edit };
|
||||||
db,
|
|
||||||
frange,
|
|
||||||
source_file,
|
|
||||||
should_compute_edit,
|
|
||||||
};
|
|
||||||
f(ctx)
|
f(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,9 +78,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
|
||||||
label: impl Into<String>,
|
label: impl Into<String>,
|
||||||
f: impl FnOnce(&mut AssistBuilder),
|
f: impl FnOnce(&mut AssistBuilder),
|
||||||
) -> Option<Assist> {
|
) -> Option<Assist> {
|
||||||
let label = AssistLabel {
|
let label = AssistLabel { label: label.into() };
|
||||||
label: label.into(),
|
|
||||||
};
|
|
||||||
if !self.should_compute_edit {
|
if !self.should_compute_edit {
|
||||||
return Some(Assist::Unresolved(label));
|
return Some(Assist::Unresolved(label));
|
||||||
}
|
}
|
||||||
|
@ -146,9 +139,6 @@ impl AssistBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(self) -> AssistAction {
|
fn build(self) -> AssistAction {
|
||||||
AssistAction {
|
AssistAction { edit: self.edit.finish(), cursor_position: self.cursor_position }
|
||||||
edit: self.edit.finish(),
|
|
||||||
cursor_position: self.cursor_position,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,31 +81,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_visibility_adds_pub_crate_to_items() {
|
fn change_visibility_adds_pub_crate_to_items() {
|
||||||
check_assist(
|
check_assist(change_visibility, "<|>fn foo() {}", "<|>pub(crate) fn foo() {}");
|
||||||
change_visibility,
|
check_assist(change_visibility, "f<|>n foo() {}", "<|>pub(crate) fn foo() {}");
|
||||||
"<|>fn foo() {}",
|
check_assist(change_visibility, "<|>struct Foo {}", "<|>pub(crate) struct Foo {}");
|
||||||
"<|>pub(crate) fn foo() {}",
|
check_assist(change_visibility, "<|>mod foo {}", "<|>pub(crate) mod foo {}");
|
||||||
);
|
check_assist(change_visibility, "<|>trait Foo {}", "<|>pub(crate) trait Foo {}");
|
||||||
check_assist(
|
|
||||||
change_visibility,
|
|
||||||
"f<|>n foo() {}",
|
|
||||||
"<|>pub(crate) fn foo() {}",
|
|
||||||
);
|
|
||||||
check_assist(
|
|
||||||
change_visibility,
|
|
||||||
"<|>struct Foo {}",
|
|
||||||
"<|>pub(crate) struct Foo {}",
|
|
||||||
);
|
|
||||||
check_assist(
|
|
||||||
change_visibility,
|
|
||||||
"<|>mod foo {}",
|
|
||||||
"<|>pub(crate) mod foo {}",
|
|
||||||
);
|
|
||||||
check_assist(
|
|
||||||
change_visibility,
|
|
||||||
"<|>trait Foo {}",
|
|
||||||
"<|>pub(crate) trait Foo {}",
|
|
||||||
);
|
|
||||||
check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
|
check_assist(change_visibility, "m<|>od {}", "<|>pub(crate) mod {}");
|
||||||
check_assist(
|
check_assist(
|
||||||
change_visibility,
|
change_visibility,
|
||||||
|
@ -125,20 +105,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_visibility_pub_to_pub_crate() {
|
fn change_visibility_pub_to_pub_crate() {
|
||||||
check_assist(
|
check_assist(change_visibility, "<|>pub fn foo() {}", "<|>pub(crate) fn foo() {}")
|
||||||
change_visibility,
|
|
||||||
"<|>pub fn foo() {}",
|
|
||||||
"<|>pub(crate) fn foo() {}",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_visibility_pub_crate_to_pub() {
|
fn change_visibility_pub_crate_to_pub() {
|
||||||
check_assist(
|
check_assist(change_visibility, "<|>pub(crate) fn foo() {}", "<|>pub fn foo() {}")
|
||||||
change_visibility,
|
|
||||||
"<|>pub(crate) fn foo() {}",
|
|
||||||
"<|>pub fn foo() {}",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -27,10 +27,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
|
||||||
let node_expr = syntax_mapping.node_expr(expr)?;
|
let node_expr = syntax_mapping.node_expr(expr)?;
|
||||||
let match_expr_ty = infer_result[node_expr].clone();
|
let match_expr_ty = infer_result[node_expr].clone();
|
||||||
let enum_def = match match_expr_ty {
|
let enum_def = match match_expr_ty {
|
||||||
Ty::Adt {
|
Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
|
||||||
def_id: AdtDef::Enum(e),
|
|
||||||
..
|
|
||||||
} => e,
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let enum_name = enum_def.name(ctx.db)?;
|
let enum_name = enum_def.name(ctx.db)?;
|
||||||
|
|
|
@ -81,11 +81,7 @@ fn anchor_stmt(expr: &ast::Expr) -> Option<(&SyntaxNode, bool)> {
|
||||||
return Some((node, false));
|
return Some((node, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(expr) = node
|
if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) {
|
||||||
.parent()
|
|
||||||
.and_then(ast::Block::cast)
|
|
||||||
.and_then(|it| it.expr())
|
|
||||||
{
|
|
||||||
if expr.syntax() == node {
|
if expr.syntax() == node {
|
||||||
return Some((node, false));
|
return Some((node, false));
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,9 +89,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
|
||||||
}
|
}
|
||||||
|
|
||||||
fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> {
|
fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> {
|
||||||
node.siblings(direction)
|
node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia())
|
||||||
.skip(1)
|
|
||||||
.find(|node| !node.kind().is_trivia())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -110,10 +108,8 @@ mod helpers {
|
||||||
) {
|
) {
|
||||||
let (before_cursor_pos, before) = extract_offset(before);
|
let (before_cursor_pos, before) = extract_offset(before);
|
||||||
let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
|
let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
|
||||||
let frange = FileRange {
|
let frange =
|
||||||
file_id,
|
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
|
||||||
range: TextRange::offset_len(before_cursor_pos, 0.into()),
|
|
||||||
};
|
|
||||||
let assist =
|
let assist =
|
||||||
AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
|
AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
|
||||||
let action = match assist {
|
let action = match assist {
|
||||||
|
@ -161,10 +157,8 @@ mod helpers {
|
||||||
) {
|
) {
|
||||||
let (before_cursor_pos, before) = extract_offset(before);
|
let (before_cursor_pos, before) = extract_offset(before);
|
||||||
let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
|
let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
|
||||||
let frange = FileRange {
|
let frange =
|
||||||
file_id,
|
FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
|
||||||
range: TextRange::offset_len(before_cursor_pos, 0.into()),
|
|
||||||
};
|
|
||||||
let assist = AssistCtx::with_ctx(&db, frange, true, assist);
|
let assist = AssistCtx::with_ctx(&db, frange, true, assist);
|
||||||
assert!(assist.is_none());
|
assert!(assist.is_none());
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,11 +30,7 @@ fn build_match_expr(
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
|
buf.push_str(&format!("match {} {{\n", expr.syntax().text()));
|
||||||
buf.push_str(&format!(
|
buf.push_str(&format!(" {} => {}\n", pat1.syntax().text(), format_arm(arm1)));
|
||||||
" {} => {}\n",
|
|
||||||
pat1.syntax().text(),
|
|
||||||
format_arm(arm1)
|
|
||||||
));
|
|
||||||
buf.push_str(&format!(" _ => {}\n", format_arm(arm2)));
|
buf.push_str(&format!(" _ => {}\n", format_arm(arm2)));
|
||||||
buf.push_str("}");
|
buf.push_str("}");
|
||||||
buf
|
buf
|
||||||
|
|
|
@ -8,9 +8,7 @@ use ra_syntax::{
|
||||||
use crate::{AssistCtx, Assist};
|
use crate::{AssistCtx, Assist};
|
||||||
|
|
||||||
pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||||
let colon_colon = ctx
|
let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?;
|
||||||
.leaf_at_offset()
|
|
||||||
.find(|leaf| leaf.kind() == COLONCOLON)?;
|
|
||||||
let path = colon_colon.parent().and_then(ast::Path::cast)?;
|
let path = colon_colon.parent().and_then(ast::Path::cast)?;
|
||||||
let top_path = generate(Some(path), |it| it.parent_path()).last()?;
|
let top_path = generate(Some(path), |it| it.parent_path()).last()?;
|
||||||
|
|
||||||
|
|
|
@ -13,18 +13,8 @@ fn main() -> Result<()> {
|
||||||
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
|
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("render-test")
|
SubCommand::with_name("render-test")
|
||||||
.arg(
|
.arg(Arg::with_name("line").long("--line").required(true).takes_value(true))
|
||||||
Arg::with_name("line")
|
.arg(Arg::with_name("file").long("--file").required(true).takes_value(true)),
|
||||||
.long("--line")
|
|
||||||
.required(true)
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("file")
|
|
||||||
.long("--file")
|
|
||||||
.required(true)
|
|
||||||
.takes_value(true),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
|
.subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
|
||||||
.subcommand(SubCommand::with_name("symbols"))
|
.subcommand(SubCommand::with_name("symbols"))
|
||||||
|
@ -108,8 +98,5 @@ fn selections(file: &SourceFile, start: u32, end: u32) -> String {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
|
.map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
|
||||||
.map(|(s, e)| format!("({} {})", s, e));
|
.map(|(s, e)| format!("({} {})", s, e));
|
||||||
join(ranges)
|
join(ranges).separator(" ").surround_with("(", ")").to_string()
|
||||||
.separator(" ")
|
|
||||||
.surround_with("(", ")")
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,7 @@ struct CrateData {
|
||||||
|
|
||||||
impl CrateData {
|
impl CrateData {
|
||||||
fn new(file_id: FileId) -> CrateData {
|
fn new(file_id: FileId) -> CrateData {
|
||||||
CrateData {
|
CrateData { file_id, dependencies: Vec::new() }
|
||||||
file_id,
|
|
||||||
dependencies: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
|
fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
|
||||||
|
@ -112,10 +109,7 @@ impl CrateGraph {
|
||||||
self.arena[&crate_id].file_id
|
self.arena[&crate_id].file_id
|
||||||
}
|
}
|
||||||
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
|
pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
|
||||||
let (&crate_id, _) = self
|
let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
|
||||||
.arena
|
|
||||||
.iter()
|
|
||||||
.find(|(_crate_id, data)| data.file_id == file_id)?;
|
|
||||||
Some(crate_id)
|
Some(crate_id)
|
||||||
}
|
}
|
||||||
pub fn dependencies<'a>(
|
pub fn dependencies<'a>(
|
||||||
|
@ -153,15 +147,9 @@ mod tests {
|
||||||
let crate1 = graph.add_crate_root(FileId(1u32));
|
let crate1 = graph.add_crate_root(FileId(1u32));
|
||||||
let crate2 = graph.add_crate_root(FileId(2u32));
|
let crate2 = graph.add_crate_root(FileId(2u32));
|
||||||
let crate3 = graph.add_crate_root(FileId(3u32));
|
let crate3 = graph.add_crate_root(FileId(3u32));
|
||||||
assert!(graph
|
assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
|
||||||
.add_dep(crate1, SmolStr::new("crate2"), crate2)
|
assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
|
||||||
.is_ok());
|
assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
|
||||||
assert!(graph
|
|
||||||
.add_dep(crate2, SmolStr::new("crate3"), crate3)
|
|
||||||
.is_ok());
|
|
||||||
assert!(graph
|
|
||||||
.add_dep(crate3, SmolStr::new("crate1"), crate1)
|
|
||||||
.is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -170,11 +158,7 @@ mod tests {
|
||||||
let crate1 = graph.add_crate_root(FileId(1u32));
|
let crate1 = graph.add_crate_root(FileId(1u32));
|
||||||
let crate2 = graph.add_crate_root(FileId(2u32));
|
let crate2 = graph.add_crate_root(FileId(2u32));
|
||||||
let crate3 = graph.add_crate_root(FileId(3u32));
|
let crate3 = graph.add_crate_root(FileId(3u32));
|
||||||
assert!(graph
|
assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
|
||||||
.add_dep(crate1, SmolStr::new("crate2"), crate2)
|
assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
|
||||||
.is_ok());
|
|
||||||
assert!(graph
|
|
||||||
.add_dep(crate2, SmolStr::new("crate3"), crate3)
|
|
||||||
.is_ok());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,11 +94,8 @@ pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
|
||||||
fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
|
fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
|
||||||
let root = db.source_root(id);
|
let root = db.source_root(id);
|
||||||
let graph = db.crate_graph();
|
let graph = db.crate_graph();
|
||||||
let res = root
|
let res =
|
||||||
.files
|
root.files.values().filter_map(|&it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
|
||||||
.values()
|
|
||||||
.filter_map(|&it| graph.crate_id_for_crate_root(it))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Arc::new(res)
|
Arc::new(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,7 @@ where
|
||||||
LOC: Clone + Eq + Hash,
|
LOC: Clone + Eq + Hash,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Loc2IdMap {
|
Loc2IdMap { id2loc: Arena::default(), loc2id: FxHashMap::default() }
|
||||||
id2loc: Arena::default(),
|
|
||||||
loc2id: FxHashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +82,7 @@ where
|
||||||
LOC: Clone + Eq + Hash,
|
LOC: Clone + Eq + Hash,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
LocationIntener {
|
LocationIntener { map: Default::default() }
|
||||||
map: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,7 @@ impl StructData {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variants(enum_def: &ast::EnumDef) -> impl Iterator<Item = &ast::EnumVariant> {
|
fn variants(enum_def: &ast::EnumDef) -> impl Iterator<Item = &ast::EnumVariant> {
|
||||||
enum_def
|
enum_def.variant_list().into_iter().flat_map(|it| it.variants())
|
||||||
.variant_list()
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|it| it.variants())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumVariant {
|
impl EnumVariant {
|
||||||
|
@ -83,9 +80,7 @@ impl EnumVariant {
|
||||||
(file_id, var)
|
(file_id, var)
|
||||||
}
|
}
|
||||||
pub(crate) fn variant_data(&self, db: &impl PersistentHirDatabase) -> Arc<VariantData> {
|
pub(crate) fn variant_data(&self, db: &impl PersistentHirDatabase) -> Arc<VariantData> {
|
||||||
db.enum_data(self.parent).variants[self.id]
|
db.enum_data(self.parent).variants[self.id].variant_data.clone()
|
||||||
.variant_data
|
|
||||||
.clone()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,14 +217,12 @@ impl StructField {
|
||||||
};
|
};
|
||||||
|
|
||||||
let field_sources = match struct_flavor {
|
let field_sources = match struct_flavor {
|
||||||
ast::StructFlavor::Tuple(fl) => fl
|
ast::StructFlavor::Tuple(fl) => {
|
||||||
.fields()
|
fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect()
|
||||||
.map(|it| FieldSource::Pos(it.to_owned()))
|
}
|
||||||
.collect(),
|
ast::StructFlavor::Named(fl) => {
|
||||||
ast::StructFlavor::Named(fl) => fl
|
fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect()
|
||||||
.fields()
|
}
|
||||||
.map(|it| FieldSource::Named(it.to_owned()))
|
|
||||||
.collect(),
|
|
||||||
ast::StructFlavor::Unit => Vec::new(),
|
ast::StructFlavor::Unit => Vec::new(),
|
||||||
};
|
};
|
||||||
let field = field_sources
|
let field = field_sources
|
||||||
|
|
|
@ -71,17 +71,7 @@ pub enum ModuleDef {
|
||||||
Trait(Trait),
|
Trait(Trait),
|
||||||
Type(Type),
|
Type(Type),
|
||||||
}
|
}
|
||||||
impl_froms!(
|
impl_froms!(ModuleDef: Module, Function, Struct, Enum, EnumVariant, Const, Static, Trait, Type);
|
||||||
ModuleDef: Module,
|
|
||||||
Function,
|
|
||||||
Struct,
|
|
||||||
Enum,
|
|
||||||
EnumVariant,
|
|
||||||
Const,
|
|
||||||
Static,
|
|
||||||
Trait,
|
|
||||||
Type
|
|
||||||
);
|
|
||||||
|
|
||||||
pub enum ModuleSource {
|
pub enum ModuleSource {
|
||||||
SourceFile(TreeArc<ast::SourceFile>),
|
SourceFile(TreeArc<ast::SourceFile>),
|
||||||
|
@ -90,13 +80,8 @@ pub enum ModuleSource {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub enum Problem {
|
pub enum Problem {
|
||||||
UnresolvedModule {
|
UnresolvedModule { candidate: RelativePathBuf },
|
||||||
candidate: RelativePathBuf,
|
NotDirOwner { move_to: RelativePathBuf, candidate: RelativePathBuf },
|
||||||
},
|
|
||||||
NotDirOwner {
|
|
||||||
move_to: RelativePathBuf,
|
|
||||||
candidate: RelativePathBuf,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
|
@ -187,8 +172,7 @@ impl Module {
|
||||||
|
|
||||||
impl Docs for Module {
|
impl Docs for Module {
|
||||||
fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
|
fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
|
||||||
self.declaration_source(db)
|
self.declaration_source(db).and_then(|it| docs_from_ast(&*it.1))
|
||||||
.and_then(|it| docs_from_ast(&*it.1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,9 +190,7 @@ pub enum FieldSource {
|
||||||
|
|
||||||
impl StructField {
|
impl StructField {
|
||||||
pub fn name(&self, db: &impl HirDatabase) -> Name {
|
pub fn name(&self, db: &impl HirDatabase) -> Name {
|
||||||
self.parent.variant_data(db).fields().unwrap()[self.id]
|
self.parent.variant_data(db).fields().unwrap()[self.id].name.clone()
|
||||||
.name
|
|
||||||
.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, FieldSource) {
|
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, FieldSource) {
|
||||||
|
@ -257,10 +239,7 @@ impl Struct {
|
||||||
.fields()
|
.fields()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|it| it.iter())
|
.flat_map(|it| it.iter())
|
||||||
.map(|(id, _)| StructField {
|
.map(|(id, _)| StructField { parent: (*self).into(), id })
|
||||||
parent: (*self).into(),
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,10 +250,7 @@ impl Struct {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|it| it.iter())
|
.flat_map(|it| it.iter())
|
||||||
.find(|(_id, data)| data.name == *name)
|
.find(|(_id, data)| data.name == *name)
|
||||||
.map(|(id, _)| StructField {
|
.map(|(id, _)| StructField { parent: (*self).into(), id })
|
||||||
parent: (*self).into(),
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
|
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
|
||||||
|
@ -292,11 +268,7 @@ impl Struct {
|
||||||
let r = self.module(db).resolver(db);
|
let r = self.module(db).resolver(db);
|
||||||
// ...and add generic params, if present
|
// ...and add generic params, if present
|
||||||
let p = self.generic_params(db);
|
let p = self.generic_params(db);
|
||||||
let r = if !p.params.is_empty() {
|
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
|
||||||
r.push_generic_params_scope(p)
|
|
||||||
} else {
|
|
||||||
r
|
|
||||||
};
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,11 +328,7 @@ impl Enum {
|
||||||
let r = self.module(db).resolver(db);
|
let r = self.module(db).resolver(db);
|
||||||
// ...and add generic params, if present
|
// ...and add generic params, if present
|
||||||
let p = self.generic_params(db);
|
let p = self.generic_params(db);
|
||||||
let r = if !p.params.is_empty() {
|
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
|
||||||
r.push_generic_params_scope(p)
|
|
||||||
} else {
|
|
||||||
r
|
|
||||||
};
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,10 +368,7 @@ impl EnumVariant {
|
||||||
.fields()
|
.fields()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|it| it.iter())
|
.flat_map(|it| it.iter())
|
||||||
.map(|(id, _)| StructField {
|
.map(|(id, _)| StructField { parent: (*self).into(), id })
|
||||||
parent: (*self).into(),
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,10 +378,7 @@ impl EnumVariant {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|it| it.iter())
|
.flat_map(|it| it.iter())
|
||||||
.find(|(_id, data)| data.name == *name)
|
.find(|(_id, data)| data.name == *name)
|
||||||
.map(|(id, _)| StructField {
|
.map(|(id, _)| StructField { parent: (*self).into(), id })
|
||||||
parent: (*self).into(),
|
|
||||||
id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,10 +450,7 @@ impl Function {
|
||||||
pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping {
|
pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping {
|
||||||
let scopes = db.expr_scopes(*self);
|
let scopes = db.expr_scopes(*self);
|
||||||
let syntax_mapping = db.body_syntax_mapping(*self);
|
let syntax_mapping = db.body_syntax_mapping(*self);
|
||||||
ScopesWithSyntaxMapping {
|
ScopesWithSyntaxMapping { scopes, syntax_mapping }
|
||||||
scopes,
|
|
||||||
syntax_mapping,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
|
pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
|
||||||
|
@ -516,11 +475,7 @@ impl Function {
|
||||||
.unwrap_or_else(|| self.module(db).resolver(db));
|
.unwrap_or_else(|| self.module(db).resolver(db));
|
||||||
// ...and add generic params, if present
|
// ...and add generic params, if present
|
||||||
let p = self.generic_params(db);
|
let p = self.generic_params(db);
|
||||||
let r = if !p.params.is_empty() {
|
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
|
||||||
r.push_generic_params_scope(p)
|
|
||||||
} else {
|
|
||||||
r
|
|
||||||
};
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,7 @@ impl FnSignature {
|
||||||
func: Function,
|
func: Function,
|
||||||
) -> Arc<FnSignature> {
|
) -> Arc<FnSignature> {
|
||||||
let (_, node) = func.source(db);
|
let (_, node) = func.source(db);
|
||||||
let name = node
|
let name = node.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
|
||||||
.name()
|
|
||||||
.map(|n| n.as_name())
|
|
||||||
.unwrap_or_else(Name::missing);
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
let mut has_self_param = false;
|
let mut has_self_param = false;
|
||||||
if let Some(param_list) = node.param_list() {
|
if let Some(param_list) = node.param_list() {
|
||||||
|
@ -61,12 +58,7 @@ impl FnSignature {
|
||||||
TypeRef::unit()
|
TypeRef::unit()
|
||||||
};
|
};
|
||||||
|
|
||||||
let sig = FnSignature {
|
let sig = FnSignature { name, params, ret_type, has_self_param };
|
||||||
name,
|
|
||||||
params,
|
|
||||||
ret_type,
|
|
||||||
has_self_param,
|
|
||||||
};
|
|
||||||
Arc::new(sig)
|
Arc::new(sig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,7 @@ impl Crate {
|
||||||
crate_graph
|
crate_graph
|
||||||
.dependencies(self.crate_id)
|
.dependencies(self.crate_id)
|
||||||
.map(|dep| {
|
.map(|dep| {
|
||||||
let krate = Crate {
|
let krate = Crate { crate_id: dep.crate_id() };
|
||||||
crate_id: dep.crate_id(),
|
|
||||||
};
|
|
||||||
let name = dep.as_name();
|
let name = dep.as_name();
|
||||||
CrateDependency { krate, name }
|
CrateDependency { krate, name }
|
||||||
})
|
})
|
||||||
|
@ -23,10 +21,7 @@ impl Crate {
|
||||||
let module_tree = db.module_tree(*self);
|
let module_tree = db.module_tree(*self);
|
||||||
let module_id = module_tree.modules().next()?;
|
let module_id = module_tree.modules().next()?;
|
||||||
|
|
||||||
let module = Module {
|
let module = Module { krate: *self, module_id };
|
||||||
krate: *self,
|
|
||||||
module_id,
|
|
||||||
};
|
|
||||||
Some(module)
|
Some(module)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,7 @@ use crate::{
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
fn with_module_id(&self, module_id: ModuleId) -> Module {
|
fn with_module_id(&self, module_id: ModuleId) -> Module {
|
||||||
Module {
|
Module { module_id, krate: self.krate }
|
||||||
module_id,
|
|
||||||
krate: self.krate,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> {
|
pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> {
|
||||||
|
@ -42,10 +39,7 @@ impl Module {
|
||||||
) -> Option<(FileId, TreeArc<ast::Module>)> {
|
) -> Option<(FileId, TreeArc<ast::Module>)> {
|
||||||
let module_tree = db.module_tree(self.krate);
|
let module_tree = db.module_tree(self.krate);
|
||||||
let link = self.module_id.parent_link(&module_tree)?;
|
let link = self.module_id.parent_link(&module_tree)?;
|
||||||
let file_id = link
|
let file_id = link.owner(&module_tree).file_id(&module_tree).as_original_file();
|
||||||
.owner(&module_tree)
|
|
||||||
.file_id(&module_tree)
|
|
||||||
.as_original_file();
|
|
||||||
let src = link.source(&module_tree, db);
|
let src = link.source(&module_tree, db);
|
||||||
Some((file_id, src))
|
Some((file_id, src))
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,9 +121,7 @@ impl BodySyntaxMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
|
pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
|
||||||
self.expr_syntax_mapping
|
self.expr_syntax_mapping.get(&SyntaxNodePtr::new(node.syntax())).cloned()
|
||||||
.get(&SyntaxNodePtr::new(node.syntax()))
|
|
||||||
.cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pat_syntax(&self, pat: PatId) -> Option<SyntaxNodePtr> {
|
pub fn pat_syntax(&self, pat: PatId) -> Option<SyntaxNodePtr> {
|
||||||
|
@ -135,9 +133,7 @@ impl BodySyntaxMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
|
pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
|
||||||
self.pat_syntax_mapping
|
self.pat_syntax_mapping.get(&SyntaxNodePtr::new(node.syntax())).cloned()
|
||||||
.get(&SyntaxNodePtr::new(node.syntax()))
|
|
||||||
.cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body(&self) -> &Arc<Body> {
|
pub fn body(&self) -> &Arc<Body> {
|
||||||
|
@ -262,11 +258,7 @@ pub struct StructLitField {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let {
|
Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> },
|
||||||
pat: PatId,
|
|
||||||
type_ref: Option<TypeRef>,
|
|
||||||
initializer: Option<ExprId>,
|
|
||||||
},
|
|
||||||
Expr(ExprId),
|
Expr(ExprId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,11 +267,7 @@ impl Expr {
|
||||||
match self {
|
match self {
|
||||||
Expr::Missing => {}
|
Expr::Missing => {}
|
||||||
Expr::Path(_) => {}
|
Expr::Path(_) => {}
|
||||||
Expr::If {
|
Expr::If { condition, then_branch, else_branch } => {
|
||||||
condition,
|
|
||||||
then_branch,
|
|
||||||
else_branch,
|
|
||||||
} => {
|
|
||||||
f(*condition);
|
f(*condition);
|
||||||
f(*then_branch);
|
f(*then_branch);
|
||||||
if let Some(else_branch) = else_branch {
|
if let Some(else_branch) = else_branch {
|
||||||
|
@ -457,11 +445,7 @@ impl Pat {
|
||||||
args.iter().map(|pat| *pat).for_each(f);
|
args.iter().map(|pat| *pat).for_each(f);
|
||||||
}
|
}
|
||||||
Pat::Ref { pat, .. } => f(*pat),
|
Pat::Ref { pat, .. } => f(*pat),
|
||||||
Pat::Slice {
|
Pat::Slice { prefix, rest, suffix } => {
|
||||||
prefix,
|
|
||||||
rest,
|
|
||||||
suffix,
|
|
||||||
} => {
|
|
||||||
let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
|
let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter());
|
||||||
total_iter.map(|pat| *pat).for_each(f);
|
total_iter.map(|pat| *pat).for_each(f);
|
||||||
}
|
}
|
||||||
|
@ -520,10 +504,7 @@ impl ExprCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_block(&mut self) -> ExprId {
|
fn empty_block(&mut self) -> ExprId {
|
||||||
let block = Expr::Block {
|
let block = Expr::Block { statements: Vec::new(), tail: None };
|
||||||
statements: Vec::new(),
|
|
||||||
tail: None,
|
|
||||||
};
|
|
||||||
self.exprs.alloc(block)
|
self.exprs.alloc(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,24 +530,10 @@ impl ExprCollector {
|
||||||
.unwrap_or_else(|| self.empty_block());
|
.unwrap_or_else(|| self.empty_block());
|
||||||
let placeholder_pat = self.pats.alloc(Pat::Missing);
|
let placeholder_pat = self.pats.alloc(Pat::Missing);
|
||||||
let arms = vec![
|
let arms = vec![
|
||||||
MatchArm {
|
MatchArm { pats: vec![pat], expr: then_branch, guard: None },
|
||||||
pats: vec![pat],
|
MatchArm { pats: vec![placeholder_pat], expr: else_branch, guard: None },
|
||||||
expr: then_branch,
|
|
||||||
guard: None,
|
|
||||||
},
|
|
||||||
MatchArm {
|
|
||||||
pats: vec![placeholder_pat],
|
|
||||||
expr: else_branch,
|
|
||||||
guard: None,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr)
|
||||||
Expr::Match {
|
|
||||||
expr: match_expr,
|
|
||||||
arms,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
|
let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
|
||||||
let then_branch = self.collect_block_opt(e.then_branch());
|
let then_branch = self.collect_block_opt(e.then_branch());
|
||||||
|
@ -577,14 +544,7 @@ impl ExprCollector {
|
||||||
self.collect_expr(expr)
|
self.collect_expr(expr)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
|
||||||
Expr::If {
|
|
||||||
condition,
|
|
||||||
then_branch,
|
|
||||||
else_branch,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprKind::BlockExpr(e) => self.collect_block_opt(e.block()),
|
ast::ExprKind::BlockExpr(e) => self.collect_block_opt(e.block()),
|
||||||
|
@ -610,14 +570,7 @@ impl ExprCollector {
|
||||||
let iterable = self.collect_expr_opt(e.iterable());
|
let iterable = self.collect_expr_opt(e.iterable());
|
||||||
let pat = self.collect_pat_opt(e.pat());
|
let pat = self.collect_pat_opt(e.pat());
|
||||||
let body = self.collect_block_opt(e.loop_body());
|
let body = self.collect_block_opt(e.loop_body());
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
|
||||||
Expr::For {
|
|
||||||
iterable,
|
|
||||||
pat,
|
|
||||||
body,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ast::ExprKind::CallExpr(e) => {
|
ast::ExprKind::CallExpr(e) => {
|
||||||
let callee = self.collect_expr_opt(e.expr());
|
let callee = self.collect_expr_opt(e.expr());
|
||||||
|
@ -635,18 +588,8 @@ impl ExprCollector {
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
let method_name = e
|
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
||||||
.name_ref()
|
self.alloc_expr(Expr::MethodCall { receiver, method_name, args }, syntax_ptr)
|
||||||
.map(|nr| nr.as_name())
|
|
||||||
.unwrap_or_else(Name::missing);
|
|
||||||
self.alloc_expr(
|
|
||||||
Expr::MethodCall {
|
|
||||||
receiver,
|
|
||||||
method_name,
|
|
||||||
args,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ast::ExprKind::MatchExpr(e) => {
|
ast::ExprKind::MatchExpr(e) => {
|
||||||
let expr = self.collect_expr_opt(e.expr());
|
let expr = self.collect_expr_opt(e.expr());
|
||||||
|
@ -668,11 +611,8 @@ impl ExprCollector {
|
||||||
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
|
self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::ExprKind::PathExpr(e) => {
|
ast::ExprKind::PathExpr(e) => {
|
||||||
let path = e
|
let path =
|
||||||
.path()
|
e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing);
|
||||||
.and_then(Path::from_ast)
|
|
||||||
.map(Expr::Path)
|
|
||||||
.unwrap_or(Expr::Missing);
|
|
||||||
self.alloc_expr(path, syntax_ptr)
|
self.alloc_expr(path, syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::ExprKind::ContinueExpr(_e) => {
|
ast::ExprKind::ContinueExpr(_e) => {
|
||||||
|
@ -721,21 +661,11 @@ impl ExprCollector {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
let spread = e.spread().map(|s| self.collect_expr(s));
|
let spread = e.spread().map(|s| self.collect_expr(s));
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::StructLit { path, fields, spread }, syntax_ptr)
|
||||||
Expr::StructLit {
|
|
||||||
path,
|
|
||||||
fields,
|
|
||||||
spread,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ast::ExprKind::FieldExpr(e) => {
|
ast::ExprKind::FieldExpr(e) => {
|
||||||
let expr = self.collect_expr_opt(e.expr());
|
let expr = self.collect_expr_opt(e.expr());
|
||||||
let name = e
|
let name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
||||||
.name_ref()
|
|
||||||
.map(|nr| nr.as_name())
|
|
||||||
.unwrap_or_else(Name::missing);
|
|
||||||
self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
|
self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::ExprKind::TryExpr(e) => {
|
ast::ExprKind::TryExpr(e) => {
|
||||||
|
@ -772,14 +702,7 @@ impl ExprCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let body = self.collect_expr_opt(e.body());
|
let body = self.collect_expr_opt(e.body());
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
|
||||||
Expr::Lambda {
|
|
||||||
args,
|
|
||||||
arg_types,
|
|
||||||
body,
|
|
||||||
},
|
|
||||||
syntax_ptr,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
ast::ExprKind::BinExpr(e) => {
|
ast::ExprKind::BinExpr(e) => {
|
||||||
let lhs = self.collect_expr_opt(e.lhs());
|
let lhs = self.collect_expr_opt(e.lhs());
|
||||||
|
@ -804,9 +727,8 @@ impl ExprCollector {
|
||||||
|
|
||||||
let lit = match child.flavor() {
|
let lit = match child.flavor() {
|
||||||
LiteralFlavor::IntNumber { suffix } => {
|
LiteralFlavor::IntNumber { suffix } => {
|
||||||
let known_name = suffix
|
let known_name =
|
||||||
.map(Name::new)
|
suffix.map(Name::new).and_then(|name| UncertainIntTy::from_name(&name));
|
||||||
.and_then(|name| UncertainIntTy::from_name(&name));
|
|
||||||
|
|
||||||
Literal::Int(
|
Literal::Int(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
@ -857,11 +779,7 @@ impl ExprCollector {
|
||||||
let pat = self.collect_pat_opt(stmt.pat());
|
let pat = self.collect_pat_opt(stmt.pat());
|
||||||
let type_ref = stmt.type_ref().map(TypeRef::from_ast);
|
let type_ref = stmt.type_ref().map(TypeRef::from_ast);
|
||||||
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
|
let initializer = stmt.initializer().map(|e| self.collect_expr(e));
|
||||||
Statement::Let {
|
Statement::Let { pat, type_ref, initializer }
|
||||||
pat,
|
|
||||||
type_ref,
|
|
||||||
initializer,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast::StmtKind::ExprStmt(stmt) => {
|
ast::StmtKind::ExprStmt(stmt) => {
|
||||||
Statement::Expr(self.collect_expr_opt(stmt.expr()))
|
Statement::Expr(self.collect_expr_opt(stmt.expr()))
|
||||||
|
@ -869,10 +787,7 @@ impl ExprCollector {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let tail = block.expr().map(|e| self.collect_expr(e));
|
let tail = block.expr().map(|e| self.collect_expr(e));
|
||||||
self.alloc_expr(
|
self.alloc_expr(Expr::Block { statements, tail }, SyntaxNodePtr::new(block.syntax()))
|
||||||
Expr::Block { statements, tail },
|
|
||||||
SyntaxNodePtr::new(block.syntax()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_block_opt(&mut self, block: Option<&ast::Block>) -> ExprId {
|
fn collect_block_opt(&mut self, block: Option<&ast::Block>) -> ExprId {
|
||||||
|
@ -886,17 +801,10 @@ impl ExprCollector {
|
||||||
fn collect_pat(&mut self, pat: &ast::Pat) -> PatId {
|
fn collect_pat(&mut self, pat: &ast::Pat) -> PatId {
|
||||||
let pattern = match pat.kind() {
|
let pattern = match pat.kind() {
|
||||||
ast::PatKind::BindPat(bp) => {
|
ast::PatKind::BindPat(bp) => {
|
||||||
let name = bp
|
let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
||||||
.name()
|
|
||||||
.map(|nr| nr.as_name())
|
|
||||||
.unwrap_or_else(Name::missing);
|
|
||||||
let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
|
let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
|
||||||
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
|
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
|
||||||
Pat::Bind {
|
Pat::Bind { name, mode: annotation, subpat }
|
||||||
name,
|
|
||||||
mode: annotation,
|
|
||||||
subpat,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast::PatKind::TupleStructPat(p) => {
|
ast::PatKind::TupleStructPat(p) => {
|
||||||
let path = p.path().and_then(Path::from_ast);
|
let path = p.path().and_then(Path::from_ast);
|
||||||
|
@ -919,9 +827,8 @@ impl ExprCollector {
|
||||||
ast::PatKind::PlaceholderPat(_) => Pat::Wild,
|
ast::PatKind::PlaceholderPat(_) => Pat::Wild,
|
||||||
ast::PatKind::StructPat(p) => {
|
ast::PatKind::StructPat(p) => {
|
||||||
let path = p.path().and_then(Path::from_ast);
|
let path = p.path().and_then(Path::from_ast);
|
||||||
let field_pat_list = p
|
let field_pat_list =
|
||||||
.field_pat_list()
|
p.field_pat_list().expect("every struct should have a field list");
|
||||||
.expect("every struct should have a field list");
|
|
||||||
let mut fields: Vec<_> = field_pat_list
|
let mut fields: Vec<_> = field_pat_list
|
||||||
.bind_pats()
|
.bind_pats()
|
||||||
.map(|bind_pat| {
|
.map(|bind_pat| {
|
||||||
|
@ -961,10 +868,7 @@ impl ExprCollector {
|
||||||
if let Some(param_list) = node.param_list() {
|
if let Some(param_list) = node.param_list() {
|
||||||
if let Some(self_param) = param_list.self_param() {
|
if let Some(self_param) = param_list.self_param() {
|
||||||
let self_param = SyntaxNodePtr::new(
|
let self_param = SyntaxNodePtr::new(
|
||||||
self_param
|
self_param.self_kw().expect("self param without self keyword").syntax(),
|
||||||
.self_kw()
|
|
||||||
.expect("self param without self keyword")
|
|
||||||
.syntax(),
|
|
||||||
);
|
);
|
||||||
let param_pat = self.alloc_pat(
|
let param_pat = self.alloc_pat(
|
||||||
Pat::Bind {
|
Pat::Bind {
|
||||||
|
|
|
@ -74,17 +74,11 @@ impl ExprScopes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_scope(&mut self) -> ScopeId {
|
fn root_scope(&mut self) -> ScopeId {
|
||||||
self.scopes.alloc(ScopeData {
|
self.scopes.alloc(ScopeData { parent: None, entries: vec![] })
|
||||||
parent: None,
|
|
||||||
entries: vec![],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
|
fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
|
||||||
self.scopes.alloc(ScopeData {
|
self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] })
|
||||||
parent: Some(parent),
|
|
||||||
entries: vec![],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
|
fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
|
||||||
|
@ -92,10 +86,7 @@ impl ExprScopes {
|
||||||
Pat::Bind { name, .. } => {
|
Pat::Bind { name, .. } => {
|
||||||
// bind can have a subpattern, but it's actually not allowed
|
// bind can have a subpattern, but it's actually not allowed
|
||||||
// to bind to things in there
|
// to bind to things in there
|
||||||
let entry = ScopeEntry {
|
let entry = ScopeEntry { name: name.clone(), pat };
|
||||||
name: name.clone(),
|
|
||||||
pat,
|
|
||||||
};
|
|
||||||
self.scopes[scope].entries.push(entry)
|
self.scopes[scope].entries.push(entry)
|
||||||
}
|
}
|
||||||
p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
|
p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
|
||||||
|
@ -104,9 +95,7 @@ impl ExprScopes {
|
||||||
|
|
||||||
fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
|
fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
|
||||||
let body = Arc::clone(&self.body);
|
let body = Arc::clone(&self.body);
|
||||||
params
|
params.iter().for_each(|pat| self.add_bindings(&body, scope, *pat));
|
||||||
.iter()
|
|
||||||
.for_each(|pat| self.add_bindings(&body, scope, *pat));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
|
fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
|
||||||
|
@ -142,9 +131,7 @@ impl ScopeEntryWithSyntax {
|
||||||
|
|
||||||
impl ScopesWithSyntaxMapping {
|
impl ScopesWithSyntaxMapping {
|
||||||
fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a {
|
fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a {
|
||||||
generate(self.scope_for(node), move |&scope| {
|
generate(self.scope_for(node), move |&scope| self.scopes.scopes[scope].parent)
|
||||||
self.scopes.scopes[scope].parent
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope_for_offset(&self, offset: TextUnit) -> Option<ScopeId> {
|
pub fn scope_for_offset(&self, offset: TextUnit) -> Option<ScopeId> {
|
||||||
|
@ -154,10 +141,7 @@ impl ScopesWithSyntaxMapping {
|
||||||
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
||||||
// find containing scope
|
// find containing scope
|
||||||
.min_by_key(|(ptr, _scope)| {
|
.min_by_key(|(ptr, _scope)| {
|
||||||
(
|
(!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len())
|
||||||
!(ptr.range().start() <= offset && offset <= ptr.range().end()),
|
|
||||||
ptr.range().len(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.map(|(ptr, scope)| self.adjust(ptr, *scope, offset))
|
.map(|(ptr, scope)| self.adjust(ptr, *scope, offset))
|
||||||
}
|
}
|
||||||
|
@ -251,9 +235,7 @@ fn compute_block_scopes(
|
||||||
) {
|
) {
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Let {
|
Statement::Let { pat, initializer, .. } => {
|
||||||
pat, initializer, ..
|
|
||||||
} => {
|
|
||||||
if let Some(expr) = initializer {
|
if let Some(expr) = initializer {
|
||||||
scopes.set_scope(*expr, scope);
|
scopes.set_scope(*expr, scope);
|
||||||
compute_expr_scopes(*expr, body, scopes, scope);
|
compute_expr_scopes(*expr, body, scopes, scope);
|
||||||
|
@ -278,21 +260,13 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
|
||||||
Expr::Block { statements, tail } => {
|
Expr::Block { statements, tail } => {
|
||||||
compute_block_scopes(&statements, *tail, body, scopes, scope);
|
compute_block_scopes(&statements, *tail, body, scopes, scope);
|
||||||
}
|
}
|
||||||
Expr::For {
|
Expr::For { iterable, pat, body: body_expr } => {
|
||||||
iterable,
|
|
||||||
pat,
|
|
||||||
body: body_expr,
|
|
||||||
} => {
|
|
||||||
compute_expr_scopes(*iterable, body, scopes, scope);
|
compute_expr_scopes(*iterable, body, scopes, scope);
|
||||||
let scope = scopes.new_scope(scope);
|
let scope = scopes.new_scope(scope);
|
||||||
scopes.add_bindings(body, scope, *pat);
|
scopes.add_bindings(body, scope, *pat);
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||||
}
|
}
|
||||||
Expr::Lambda {
|
Expr::Lambda { args, body: body_expr, .. } => {
|
||||||
args,
|
|
||||||
body: body_expr,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let scope = scopes.new_scope(scope);
|
let scope = scopes.new_scope(scope);
|
||||||
scopes.add_params_bindings(scope, &args);
|
scopes.add_params_bindings(scope, &args);
|
||||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||||
|
@ -341,9 +315,7 @@ mod tests {
|
||||||
let file = SourceFile::parse(&code);
|
let file = SourceFile::parse(&code);
|
||||||
let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
|
let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let irrelevant_function = Function {
|
let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) };
|
||||||
id: crate::ids::FunctionId::from_raw(0.into()),
|
|
||||||
};
|
|
||||||
let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
|
let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
|
||||||
let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
|
let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
|
||||||
let scopes = ScopesWithSyntaxMapping {
|
let scopes = ScopesWithSyntaxMapping {
|
||||||
|
@ -444,9 +416,7 @@ mod tests {
|
||||||
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
|
let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
|
|
||||||
let irrelevant_function = Function {
|
let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) };
|
||||||
id: crate::ids::FunctionId::from_raw(0.into()),
|
|
||||||
};
|
|
||||||
let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
|
let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def);
|
||||||
let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
|
let scopes = ExprScopes::new(Arc::clone(body_hir.body()));
|
||||||
let scopes = ScopesWithSyntaxMapping {
|
let scopes = ScopesWithSyntaxMapping {
|
||||||
|
|
|
@ -58,14 +58,8 @@ impl GenericParams {
|
||||||
|
|
||||||
fn fill_params(&mut self, params: &ast::TypeParamList) {
|
fn fill_params(&mut self, params: &ast::TypeParamList) {
|
||||||
for (idx, type_param) in params.type_params().enumerate() {
|
for (idx, type_param) in params.type_params().enumerate() {
|
||||||
let name = type_param
|
let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
|
||||||
.name()
|
let param = GenericParam { idx: idx as u32, name };
|
||||||
.map(AsName::as_name)
|
|
||||||
.unwrap_or_else(Name::missing);
|
|
||||||
let param = GenericParam {
|
|
||||||
idx: idx as u32,
|
|
||||||
name,
|
|
||||||
};
|
|
||||||
self.params.push(param);
|
self.params.push(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,11 +169,7 @@ impl<N: AstNode> Hash for ItemLoc<N> {
|
||||||
|
|
||||||
impl<N: AstNode> Clone for ItemLoc<N> {
|
impl<N: AstNode> Clone for ItemLoc<N> {
|
||||||
fn clone(&self) -> ItemLoc<N> {
|
fn clone(&self) -> ItemLoc<N> {
|
||||||
ItemLoc {
|
ItemLoc { module: self.module, raw: self.raw, _ty: PhantomData }
|
||||||
module: self.module,
|
|
||||||
raw: self.raw,
|
|
||||||
_ty: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,11 +182,7 @@ pub(crate) struct LocationCtx<DB> {
|
||||||
|
|
||||||
impl<'a, DB: PersistentHirDatabase> LocationCtx<&'a DB> {
|
impl<'a, DB: PersistentHirDatabase> LocationCtx<&'a DB> {
|
||||||
pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
|
pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
|
||||||
LocationCtx {
|
LocationCtx { db, module, file_id }
|
||||||
db,
|
|
||||||
module,
|
|
||||||
file_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
|
pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
|
||||||
where
|
where
|
||||||
|
@ -205,15 +197,9 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
|
||||||
fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>;
|
fn interner(interner: &HirInterner) -> &LocationIntener<ItemLoc<N>, Self>;
|
||||||
fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self {
|
fn from_ast(ctx: LocationCtx<&impl PersistentHirDatabase>, ast: &N) -> Self {
|
||||||
let items = ctx.db.file_items(ctx.file_id);
|
let items = ctx.db.file_items(ctx.file_id);
|
||||||
let raw = SourceItemId {
|
let raw =
|
||||||
file_id: ctx.file_id,
|
SourceItemId { file_id: ctx.file_id, item_id: items.id_of(ctx.file_id, ast.syntax()) };
|
||||||
item_id: items.id_of(ctx.file_id, ast.syntax()),
|
let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
|
||||||
};
|
|
||||||
let loc = ItemLoc {
|
|
||||||
module: ctx.module,
|
|
||||||
raw,
|
|
||||||
_ty: PhantomData,
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::interner(ctx.db.as_ref()).loc2id(&loc)
|
Self::interner(ctx.db.as_ref()).loc2id(&loc)
|
||||||
}
|
}
|
||||||
|
@ -221,9 +207,8 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
|
||||||
let int = Self::interner(db.as_ref());
|
let int = Self::interner(db.as_ref());
|
||||||
let loc = int.id2loc(self);
|
let loc = int.id2loc(self);
|
||||||
let syntax = db.file_item(loc.raw);
|
let syntax = db.file_item(loc.raw);
|
||||||
let ast = N::cast(&syntax)
|
let ast =
|
||||||
.unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw))
|
N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
|
||||||
.to_owned();
|
|
||||||
(loc.raw.file_id, ast)
|
(loc.raw.file_id, ast)
|
||||||
}
|
}
|
||||||
fn module(self, db: &impl HirDatabase) -> Module {
|
fn module(self, db: &impl HirDatabase) -> Module {
|
||||||
|
@ -317,10 +302,7 @@ pub struct SourceFileItems {
|
||||||
|
|
||||||
impl SourceFileItems {
|
impl SourceFileItems {
|
||||||
pub(crate) fn new(file_id: HirFileId, source_file: &SourceFile) -> SourceFileItems {
|
pub(crate) fn new(file_id: HirFileId, source_file: &SourceFile) -> SourceFileItems {
|
||||||
let mut res = SourceFileItems {
|
let mut res = SourceFileItems { file_id, arena: Arena::default() };
|
||||||
file_id,
|
|
||||||
arena: Arena::default(),
|
|
||||||
};
|
|
||||||
res.init(source_file);
|
res.init(source_file);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,17 +50,11 @@ impl ImplBlock {
|
||||||
item: ImplItem,
|
item: ImplItem,
|
||||||
) -> Option<ImplBlock> {
|
) -> Option<ImplBlock> {
|
||||||
let impl_id = *module_impl_blocks.impls_by_def.get(&item)?;
|
let impl_id = *module_impl_blocks.impls_by_def.get(&item)?;
|
||||||
Some(ImplBlock {
|
Some(ImplBlock { module_impl_blocks, impl_id })
|
||||||
module_impl_blocks,
|
|
||||||
impl_id,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_id(module_impl_blocks: Arc<ModuleImplBlocks>, impl_id: ImplId) -> ImplBlock {
|
pub(crate) fn from_id(module_impl_blocks: Arc<ModuleImplBlocks>, impl_id: ImplId) -> ImplBlock {
|
||||||
ImplBlock {
|
ImplBlock { module_impl_blocks, impl_id }
|
||||||
module_impl_blocks,
|
|
||||||
impl_id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> ImplId {
|
pub fn id(&self) -> ImplId {
|
||||||
|
@ -144,11 +138,7 @@ impl ImplData {
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
ImplData {
|
ImplData { target_trait, target_type, items }
|
||||||
target_trait,
|
|
||||||
target_type,
|
|
||||||
items,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn target_trait(&self) -> Option<&TypeRef> {
|
pub fn target_trait(&self) -> Option<&TypeRef> {
|
||||||
|
@ -212,10 +202,9 @@ impl ModuleImplBlocks {
|
||||||
let file_id: HirFileId = file_id.into();
|
let file_id: HirFileId = file_id.into();
|
||||||
let node = match &module_source {
|
let node = match &module_source {
|
||||||
ModuleSource::SourceFile(node) => node.syntax(),
|
ModuleSource::SourceFile(node) => node.syntax(),
|
||||||
ModuleSource::Module(node) => node
|
ModuleSource::Module(node) => {
|
||||||
.item_list()
|
node.item_list().expect("inline module should have item list").syntax()
|
||||||
.expect("inline module should have item list")
|
}
|
||||||
.syntax(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
|
for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
|
||||||
|
|
|
@ -48,9 +48,7 @@ impl MacroDef {
|
||||||
|
|
||||||
let input = {
|
let input = {
|
||||||
let arg = macro_call.token_tree()?.syntax();
|
let arg = macro_call.token_tree()?.syntax();
|
||||||
MacroInput {
|
MacroInput { text: arg.text().to_string() }
|
||||||
text: arg.text().to_string(),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Some((def, input))
|
Some((def, input))
|
||||||
}
|
}
|
||||||
|
@ -68,20 +66,14 @@ impl MacroDef {
|
||||||
let ptr = SyntaxNodePtr::new(array_expr.syntax());
|
let ptr = SyntaxNodePtr::new(array_expr.syntax());
|
||||||
let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text));
|
let src_range = TextRange::offset_len(0.into(), TextUnit::of_str(&input.text));
|
||||||
let ranges_map = vec![(src_range, array_expr.syntax().range())];
|
let ranges_map = vec![(src_range, array_expr.syntax().range())];
|
||||||
let res = MacroExpansion {
|
let res = MacroExpansion { text, ranges_map, ptr };
|
||||||
text,
|
|
||||||
ranges_map,
|
|
||||||
ptr,
|
|
||||||
};
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
fn expand_query_group(self, input: MacroInput) -> Option<MacroExpansion> {
|
fn expand_query_group(self, input: MacroInput) -> Option<MacroExpansion> {
|
||||||
let anchor = "trait ";
|
let anchor = "trait ";
|
||||||
let pos = input.text.find(anchor)? + anchor.len();
|
let pos = input.text.find(anchor)? + anchor.len();
|
||||||
let trait_name = input.text[pos..]
|
let trait_name =
|
||||||
.chars()
|
input.text[pos..].chars().take_while(|c| c.is_alphabetic()).collect::<String>();
|
||||||
.take_while(|c| c.is_alphabetic())
|
|
||||||
.collect::<String>();
|
|
||||||
if trait_name.is_empty() {
|
if trait_name.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -92,11 +84,7 @@ impl MacroDef {
|
||||||
let name = trait_def.name()?;
|
let name = trait_def.name()?;
|
||||||
let ptr = SyntaxNodePtr::new(trait_def.syntax());
|
let ptr = SyntaxNodePtr::new(trait_def.syntax());
|
||||||
let ranges_map = vec![(src_range, name.syntax().range())];
|
let ranges_map = vec![(src_range, name.syntax().range())];
|
||||||
let res = MacroExpansion {
|
let res = MacroExpansion { text, ranges_map, ptr };
|
||||||
text,
|
|
||||||
ranges_map,
|
|
||||||
ptr,
|
|
||||||
};
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,7 @@ impl MockDatabase {
|
||||||
let mut source_root = SourceRoot::default();
|
let mut source_root = SourceRoot::default();
|
||||||
for entry in parse_fixture(fixture) {
|
for entry in parse_fixture(fixture) {
|
||||||
if entry.text.contains(CURSOR_MARKER) {
|
if entry.text.contains(CURSOR_MARKER) {
|
||||||
assert!(
|
assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
|
||||||
position.is_none(),
|
|
||||||
"only one marker (<|>) per fixture is allowed"
|
|
||||||
);
|
|
||||||
position = Some(self.add_file_with_position(
|
position = Some(self.add_file_with_position(
|
||||||
source_root_id,
|
source_root_id,
|
||||||
&mut source_root,
|
&mut source_root,
|
||||||
|
|
|
@ -153,10 +153,8 @@ impl ModuleTree {
|
||||||
file_id: HirFileId,
|
file_id: HirFileId,
|
||||||
decl_id: Option<SourceFileItemId>,
|
decl_id: Option<SourceFileItemId>,
|
||||||
) -> Option<ModuleId> {
|
) -> Option<ModuleId> {
|
||||||
let (res, _) = self
|
let (res, _) =
|
||||||
.mods
|
self.mods.iter().find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
|
||||||
.iter()
|
|
||||||
.find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,18 +176,10 @@ impl ModuleTree {
|
||||||
decl_id: Option<SourceFileItemId>,
|
decl_id: Option<SourceFileItemId>,
|
||||||
) -> ModuleId {
|
) -> ModuleId {
|
||||||
let is_root = parent.is_none();
|
let is_root = parent.is_none();
|
||||||
let id = self.alloc_mod(ModuleData {
|
let id = self.alloc_mod(ModuleData { file_id, decl_id, parent, children: Vec::new() });
|
||||||
file_id,
|
|
||||||
decl_id,
|
|
||||||
parent,
|
|
||||||
children: Vec::new(),
|
|
||||||
});
|
|
||||||
for sub in db.submodules(file_id, decl_id).iter() {
|
for sub in db.submodules(file_id, decl_id).iter() {
|
||||||
let link = self.alloc_link(LinkData {
|
let link = self.alloc_link(LinkData {
|
||||||
source: SourceItemId {
|
source: SourceItemId { file_id, item_id: sub.decl_id },
|
||||||
file_id,
|
|
||||||
item_id: sub.decl_id,
|
|
||||||
},
|
|
||||||
name: sub.name.clone(),
|
name: sub.name.clone(),
|
||||||
owner: id,
|
owner: id,
|
||||||
points_to: Vec::new(),
|
points_to: Vec::new(),
|
||||||
|
@ -244,9 +234,7 @@ impl ModuleId {
|
||||||
Some(tree.links[link].owner)
|
Some(tree.links[link].owner)
|
||||||
}
|
}
|
||||||
pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
|
pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
|
||||||
generate(Some(self), move |it| it.parent(tree))
|
generate(Some(self), move |it| it.parent(tree)).last().unwrap()
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
|
pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
|
||||||
let link = tree.mods[self]
|
let link = tree.mods[self]
|
||||||
|
|
|
@ -83,40 +83,25 @@ pub struct PerNs<T> {
|
||||||
|
|
||||||
impl<T> Default for PerNs<T> {
|
impl<T> Default for PerNs<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
PerNs {
|
PerNs { types: None, values: None }
|
||||||
types: None,
|
|
||||||
values: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> PerNs<T> {
|
impl<T> PerNs<T> {
|
||||||
pub fn none() -> PerNs<T> {
|
pub fn none() -> PerNs<T> {
|
||||||
PerNs {
|
PerNs { types: None, values: None }
|
||||||
types: None,
|
|
||||||
values: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(t: T) -> PerNs<T> {
|
pub fn values(t: T) -> PerNs<T> {
|
||||||
PerNs {
|
PerNs { types: None, values: Some(t) }
|
||||||
types: None,
|
|
||||||
values: Some(t),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types(t: T) -> PerNs<T> {
|
pub fn types(t: T) -> PerNs<T> {
|
||||||
PerNs {
|
PerNs { types: Some(t), values: None }
|
||||||
types: Some(t),
|
|
||||||
values: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn both(types: T, values: T) -> PerNs<T> {
|
pub fn both(types: T, values: T) -> PerNs<T> {
|
||||||
PerNs {
|
PerNs { types: Some(types), values: Some(values) }
|
||||||
types: Some(types),
|
|
||||||
values: Some(values),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool {
|
pub fn is_none(&self) -> bool {
|
||||||
|
@ -147,31 +132,19 @@ impl<T> PerNs<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_ref(&self) -> PerNs<&T> {
|
pub fn as_ref(&self) -> PerNs<&T> {
|
||||||
PerNs {
|
PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
|
||||||
types: self.types.as_ref(),
|
|
||||||
values: self.values.as_ref(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn combine(self, other: PerNs<T>) -> PerNs<T> {
|
pub fn combine(self, other: PerNs<T>) -> PerNs<T> {
|
||||||
PerNs {
|
PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
|
||||||
types: self.types.or(other.types),
|
|
||||||
values: self.values.or(other.values),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
|
pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
|
||||||
PerNs {
|
PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
|
||||||
types: self.types.and_then(&f),
|
|
||||||
values: self.values.and_then(&f),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
|
pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
|
||||||
PerNs {
|
PerNs { types: self.types.map(&f), values: self.values.map(&f) }
|
||||||
types: self.types.map(&f),
|
|
||||||
values: self.values.map(&f),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +206,7 @@ where
|
||||||
for dep in self.krate.dependencies(self.db) {
|
for dep in self.krate.dependencies(self.db) {
|
||||||
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
|
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
|
||||||
if let Some(module) = dep.krate.root_module(self.db) {
|
if let Some(module) = dep.krate.root_module(self.db) {
|
||||||
self.result
|
self.result.extern_prelude.insert(dep.name.clone(), module.into());
|
||||||
.extern_prelude
|
|
||||||
.insert(dep.name.clone(), module.into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,17 +216,11 @@ where
|
||||||
for (import_id, import_data) in input.imports.iter() {
|
for (import_id, import_data) in input.imports.iter() {
|
||||||
if let Some(last_segment) = import_data.path.segments.iter().last() {
|
if let Some(last_segment) = import_data.path.segments.iter().last() {
|
||||||
if !import_data.is_glob {
|
if !import_data.is_glob {
|
||||||
let name = import_data
|
let name =
|
||||||
.alias
|
import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone());
|
||||||
.clone()
|
module_items
|
||||||
.unwrap_or_else(|| last_segment.name.clone());
|
.items
|
||||||
module_items.items.insert(
|
.insert(name, Resolution { def: PerNs::none(), import: Some(import_id) });
|
||||||
name,
|
|
||||||
Resolution {
|
|
||||||
def: PerNs::none(),
|
|
||||||
import: Some(import_id),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,10 +232,7 @@ where
|
||||||
|
|
||||||
// Populate modules
|
// Populate modules
|
||||||
for (name, module_id) in module_id.children(&self.module_tree) {
|
for (name, module_id) in module_id.children(&self.module_tree) {
|
||||||
let module = Module {
|
let module = Module { module_id, krate: self.krate };
|
||||||
module_id,
|
|
||||||
krate: self.krate,
|
|
||||||
};
|
|
||||||
self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
|
self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,20 +267,13 @@ where
|
||||||
if import.is_glob {
|
if import.is_glob {
|
||||||
return ReachedFixedPoint::Yes;
|
return ReachedFixedPoint::Yes;
|
||||||
};
|
};
|
||||||
let original_module = Module {
|
let original_module = Module { krate: self.krate, module_id };
|
||||||
krate: self.krate,
|
|
||||||
module_id,
|
|
||||||
};
|
|
||||||
let (def, reached_fixedpoint) =
|
let (def, reached_fixedpoint) =
|
||||||
self.result
|
self.result.resolve_path_fp(self.db, original_module, &import.path);
|
||||||
.resolve_path_fp(self.db, original_module, &import.path);
|
|
||||||
|
|
||||||
if reached_fixedpoint == ReachedFixedPoint::Yes {
|
if reached_fixedpoint == ReachedFixedPoint::Yes {
|
||||||
let last_segment = import.path.segments.last().unwrap();
|
let last_segment = import.path.segments.last().unwrap();
|
||||||
let name = import
|
let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
|
||||||
.alias
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| last_segment.name.clone());
|
|
||||||
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
||||||
|
|
||||||
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
||||||
|
@ -330,10 +285,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update(module_id, |items| {
|
self.update(module_id, |items| {
|
||||||
let res = Resolution {
|
let res = Resolution { def, import: Some(import_id) };
|
||||||
def,
|
|
||||||
import: Some(import_id),
|
|
||||||
};
|
|
||||||
items.items.insert(name, res);
|
items.items.insert(name, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -358,12 +310,7 @@ impl ItemMap {
|
||||||
let module_tree = db.module_tree(krate);
|
let module_tree = db.module_tree(krate);
|
||||||
let input = module_tree
|
let input = module_tree
|
||||||
.modules()
|
.modules()
|
||||||
.map(|module_id| {
|
.map(|module_id| (module_id, db.lower_module_module(Module { krate, module_id })))
|
||||||
(
|
|
||||||
module_id,
|
|
||||||
db.lower_module_module(Module { krate, module_id }),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<FxHashMap<_, _>>();
|
.collect::<FxHashMap<_, _>>();
|
||||||
|
|
||||||
let resolver = Resolver::new(db, &input, krate);
|
let resolver = Resolver::new(db, &input, krate);
|
||||||
|
|
|
@ -82,13 +82,9 @@ impl LoweredModule {
|
||||||
let mut source_map = ImportSourceMap::default();
|
let mut source_map = ImportSourceMap::default();
|
||||||
let mut res = LoweredModule::default();
|
let mut res = LoweredModule::default();
|
||||||
match source {
|
match source {
|
||||||
ModuleSource::SourceFile(it) => res.fill(
|
ModuleSource::SourceFile(it) => {
|
||||||
&mut source_map,
|
res.fill(&mut source_map, db, module, file_id, &mut it.items_with_macros())
|
||||||
db,
|
}
|
||||||
module,
|
|
||||||
file_id,
|
|
||||||
&mut it.items_with_macros(),
|
|
||||||
),
|
|
||||||
ModuleSource::Module(it) => {
|
ModuleSource::Module(it) => {
|
||||||
if let Some(item_list) = it.item_list() {
|
if let Some(item_list) = it.item_list() {
|
||||||
res.fill(
|
res.fill(
|
||||||
|
@ -121,10 +117,8 @@ impl LoweredModule {
|
||||||
}
|
}
|
||||||
ast::ItemOrMacro::Macro(macro_call) => {
|
ast::ItemOrMacro::Macro(macro_call) => {
|
||||||
let item_id = file_items.id_of_unchecked(macro_call.syntax());
|
let item_id = file_items.id_of_unchecked(macro_call.syntax());
|
||||||
let loc = MacroCallLoc {
|
let loc =
|
||||||
module,
|
MacroCallLoc { module, source_item_id: SourceItemId { file_id, item_id } };
|
||||||
source_item_id: SourceItemId { file_id, item_id },
|
|
||||||
};
|
|
||||||
let id = loc.id(db);
|
let id = loc.id(db);
|
||||||
let file_id = HirFileId::from(id);
|
let file_id = HirFileId::from(id);
|
||||||
//FIXME: expand recursively
|
//FIXME: expand recursively
|
||||||
|
@ -163,22 +157,19 @@ impl LoweredModule {
|
||||||
ast::ModuleItemKind::FnDef(it) => {
|
ast::ModuleItemKind::FnDef(it) => {
|
||||||
if let Some(name) = it.name() {
|
if let Some(name) = it.name() {
|
||||||
let func = Function { id: ctx.to_def(it) };
|
let func = Function { id: ctx.to_def(it) };
|
||||||
self.declarations
|
self.declarations.insert(name.as_name(), PerNs::values(func.into()));
|
||||||
.insert(name.as_name(), PerNs::values(func.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ModuleItemKind::TraitDef(it) => {
|
ast::ModuleItemKind::TraitDef(it) => {
|
||||||
if let Some(name) = it.name() {
|
if let Some(name) = it.name() {
|
||||||
let t = Trait { id: ctx.to_def(it) };
|
let t = Trait { id: ctx.to_def(it) };
|
||||||
self.declarations
|
self.declarations.insert(name.as_name(), PerNs::types(t.into()));
|
||||||
.insert(name.as_name(), PerNs::types(t.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ModuleItemKind::TypeDef(it) => {
|
ast::ModuleItemKind::TypeDef(it) => {
|
||||||
if let Some(name) = it.name() {
|
if let Some(name) = it.name() {
|
||||||
let t = Type { id: ctx.to_def(it) };
|
let t = Type { id: ctx.to_def(it) };
|
||||||
self.declarations
|
self.declarations.insert(name.as_name(), PerNs::types(t.into()));
|
||||||
.insert(name.as_name(), PerNs::types(t.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ModuleItemKind::ImplBlock(_) => {
|
ast::ModuleItemKind::ImplBlock(_) => {
|
||||||
|
@ -207,15 +198,13 @@ impl LoweredModule {
|
||||||
ast::ModuleItemKind::ConstDef(it) => {
|
ast::ModuleItemKind::ConstDef(it) => {
|
||||||
if let Some(name) = it.name() {
|
if let Some(name) = it.name() {
|
||||||
let c = Const { id: ctx.to_def(it) };
|
let c = Const { id: ctx.to_def(it) };
|
||||||
self.declarations
|
self.declarations.insert(name.as_name(), PerNs::values(c.into()));
|
||||||
.insert(name.as_name(), PerNs::values(c.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ModuleItemKind::StaticDef(it) => {
|
ast::ModuleItemKind::StaticDef(it) => {
|
||||||
if let Some(name) = it.name() {
|
if let Some(name) = it.name() {
|
||||||
let s = Static { id: ctx.to_def(it) };
|
let s = Static { id: ctx.to_def(it) };
|
||||||
self.declarations
|
self.declarations.insert(name.as_name(), PerNs::values(s.into()));
|
||||||
.insert(name.as_name(), PerNs::values(s.into()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ModuleItemKind::Module(_) => {
|
ast::ModuleItemKind::Module(_) => {
|
||||||
|
|
|
@ -42,19 +42,11 @@ fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
lines.sort();
|
lines.sort();
|
||||||
let actual = lines.join("\n");
|
let actual = lines.join("\n");
|
||||||
let expected = expected
|
let expected = expected.trim().lines().map(|it| it.trim()).collect::<Vec<_>>().join("\n");
|
||||||
.trim()
|
|
||||||
.lines()
|
|
||||||
.map(|it| it.trim())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n");
|
|
||||||
assert_eq_text!(&expected, &actual);
|
assert_eq_text!(&expected, &actual);
|
||||||
|
|
||||||
fn dump_resolution(resolution: &Resolution) -> &'static str {
|
fn dump_resolution(resolution: &Resolution) -> &'static str {
|
||||||
match (
|
match (resolution.def.types.is_some(), resolution.def.values.is_some()) {
|
||||||
resolution.def.types.is_some(),
|
|
||||||
resolution.def.values.is_some(),
|
|
||||||
) {
|
|
||||||
(true, true) => "t v",
|
(true, true) => "t v",
|
||||||
(true, false) => "t",
|
(true, false) => "t",
|
||||||
(false, true) => "v",
|
(false, true) => "v",
|
||||||
|
@ -314,9 +306,7 @@ fn item_map_across_crates() {
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
let main_crate = crate_graph.add_crate_root(main_id);
|
let main_crate = crate_graph.add_crate_root(main_id);
|
||||||
let lib_crate = crate_graph.add_crate_root(lib_id);
|
let lib_crate = crate_graph.add_crate_root(lib_id);
|
||||||
crate_graph
|
crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
|
||||||
.add_dep(main_crate, "test_crate".into(), lib_crate)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
db.set_crate_graph(Arc::new(crate_graph));
|
db.set_crate_graph(Arc::new(crate_graph));
|
||||||
|
|
||||||
|
@ -357,9 +347,7 @@ fn extern_crate_rename() {
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
let main_crate = crate_graph.add_crate_root(main_id);
|
let main_crate = crate_graph.add_crate_root(main_id);
|
||||||
let lib_crate = crate_graph.add_crate_root(lib_id);
|
let lib_crate = crate_graph.add_crate_root(lib_id);
|
||||||
crate_graph
|
crate_graph.add_dep(main_crate, "alloc".into(), lib_crate).unwrap();
|
||||||
.add_dep(main_crate, "alloc".into(), lib_crate)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
db.set_crate_graph(Arc::new(crate_graph));
|
db.set_crate_graph(Arc::new(crate_graph));
|
||||||
|
|
||||||
|
@ -406,9 +394,7 @@ fn import_across_source_roots() {
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
let main_crate = crate_graph.add_crate_root(main_id);
|
let main_crate = crate_graph.add_crate_root(main_id);
|
||||||
let lib_crate = crate_graph.add_crate_root(lib_id);
|
let lib_crate = crate_graph.add_crate_root(lib_id);
|
||||||
crate_graph
|
crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
|
||||||
.add_dep(main_crate, "test_crate".into(), lib_crate)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
db.set_crate_graph(Arc::new(crate_graph));
|
db.set_crate_graph(Arc::new(crate_graph));
|
||||||
|
|
||||||
|
@ -447,9 +433,7 @@ fn reexport_across_crates() {
|
||||||
let mut crate_graph = CrateGraph::default();
|
let mut crate_graph = CrateGraph::default();
|
||||||
let main_crate = crate_graph.add_crate_root(main_id);
|
let main_crate = crate_graph.add_crate_root(main_id);
|
||||||
let lib_crate = crate_graph.add_crate_root(lib_id);
|
let lib_crate = crate_graph.add_crate_root(lib_id);
|
||||||
crate_graph
|
crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate).unwrap();
|
||||||
.add_dep(main_crate, "test_crate".into(), lib_crate)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
db.set_crate_graph(Arc::new(crate_graph));
|
db.set_crate_graph(Arc::new(crate_graph));
|
||||||
|
|
||||||
|
@ -482,11 +466,7 @@ fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
|
||||||
let events = db.log_executed(|| {
|
let events = db.log_executed(|| {
|
||||||
db.item_map(krate);
|
db.item_map(krate);
|
||||||
});
|
});
|
||||||
assert!(
|
assert!(!format!("{:?}", events).contains("item_map"), "{:#?}", events)
|
||||||
!format!("{:?}", events).contains("item_map"),
|
|
||||||
"{:#?}",
|
|
||||||
events
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,14 +66,9 @@ impl Path {
|
||||||
|
|
||||||
match segment.kind()? {
|
match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => {
|
ast::PathSegmentKind::Name(name) => {
|
||||||
let args = segment
|
let args =
|
||||||
.type_arg_list()
|
segment.type_arg_list().and_then(GenericArgs::from_ast).map(Arc::new);
|
||||||
.and_then(GenericArgs::from_ast)
|
let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
|
||||||
.map(Arc::new);
|
|
||||||
let segment = PathSegment {
|
|
||||||
name: name.as_name(),
|
|
||||||
args_and_bindings: args,
|
|
||||||
};
|
|
||||||
segments.push(segment);
|
segments.push(segment);
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::CrateKw => {
|
ast::PathSegmentKind::CrateKw => {
|
||||||
|
@ -153,10 +148,7 @@ impl From<Name> for Path {
|
||||||
fn from(name: Name) -> Path {
|
fn from(name: Name) -> Path {
|
||||||
Path {
|
Path {
|
||||||
kind: PathKind::Plain,
|
kind: PathKind::Plain,
|
||||||
segments: vec![PathSegment {
|
segments: vec![PathSegment { name, args_and_bindings: None }],
|
||||||
name,
|
|
||||||
args_and_bindings: None,
|
|
||||||
}],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,18 +201,13 @@ fn expand_use_tree<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_path(prefix: Option<Path>, path: &ast::Path) -> Option<Path> {
|
fn convert_path(prefix: Option<Path>, path: &ast::Path) -> Option<Path> {
|
||||||
let prefix = if let Some(qual) = path.qualifier() {
|
let prefix =
|
||||||
Some(convert_path(prefix, qual)?)
|
if let Some(qual) = path.qualifier() { Some(convert_path(prefix, qual)?) } else { prefix };
|
||||||
} else {
|
|
||||||
prefix
|
|
||||||
};
|
|
||||||
let segment = path.segment()?;
|
let segment = path.segment()?;
|
||||||
let res = match segment.kind()? {
|
let res = match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => {
|
ast::PathSegmentKind::Name(name) => {
|
||||||
let mut res = prefix.unwrap_or_else(|| Path {
|
let mut res = prefix
|
||||||
kind: PathKind::Plain,
|
.unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) });
|
||||||
segments: Vec::with_capacity(1),
|
|
||||||
});
|
|
||||||
res.segments.push(PathSegment {
|
res.segments.push(PathSegment {
|
||||||
name: name.as_name(),
|
name: name.as_name(),
|
||||||
args_and_bindings: None, // no type args in use
|
args_and_bindings: None, // no type args in use
|
||||||
|
@ -231,28 +218,19 @@ fn convert_path(prefix: Option<Path>, path: &ast::Path) -> Option<Path> {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path {
|
Path { kind: PathKind::Crate, segments: Vec::new() }
|
||||||
kind: PathKind::Crate,
|
|
||||||
segments: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::SelfKw => {
|
ast::PathSegmentKind::SelfKw => {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path {
|
Path { kind: PathKind::Self_, segments: Vec::new() }
|
||||||
kind: PathKind::Self_,
|
|
||||||
segments: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast::PathSegmentKind::SuperKw => {
|
ast::PathSegmentKind::SuperKw => {
|
||||||
if prefix.is_some() {
|
if prefix.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Path {
|
Path { kind: PathKind::Super, segments: Vec::new() }
|
||||||
kind: PathKind::Super,
|
|
||||||
segments: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
|
|
@ -23,7 +23,5 @@ pub(super) fn file_item(
|
||||||
source_item_id: SourceItemId,
|
source_item_id: SourceItemId,
|
||||||
) -> TreeArc<SyntaxNode> {
|
) -> TreeArc<SyntaxNode> {
|
||||||
let source_file = db.hir_parse(source_item_id.file_id);
|
let source_file = db.hir_parse(source_item_id.file_id);
|
||||||
db.file_items(source_item_id.file_id)[source_item_id.item_id]
|
db.file_items(source_item_id.file_id)[source_item_id.item_id].to_node(&source_file).to_owned()
|
||||||
.to_node(&source_file)
|
|
||||||
.to_owned()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,10 +138,7 @@ impl Resolver {
|
||||||
expr_scopes: Arc<ExprScopes>,
|
expr_scopes: Arc<ExprScopes>,
|
||||||
scope_id: ScopeId,
|
scope_id: ScopeId,
|
||||||
) -> Resolver {
|
) -> Resolver {
|
||||||
self.push_scope(Scope::ExprScope(ExprScope {
|
self.push_scope(Scope::ExprScope(ExprScope { expr_scopes, scope_id }))
|
||||||
expr_scopes,
|
|
||||||
scope_id,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,11 +167,8 @@ impl Scope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ExprScope(e) => {
|
Scope::ExprScope(e) => {
|
||||||
let entry = e
|
let entry =
|
||||||
.expr_scopes
|
e.expr_scopes.entries(e.scope_id).iter().find(|entry| entry.name() == name);
|
||||||
.entries(e.scope_id)
|
|
||||||
.iter()
|
|
||||||
.find(|entry| entry.name() == name);
|
|
||||||
match entry {
|
match entry {
|
||||||
Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())),
|
Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())),
|
||||||
None => PerNs::none(),
|
None => PerNs::none(),
|
||||||
|
@ -193,35 +187,24 @@ impl Scope {
|
||||||
// def: m.module.into(),
|
// def: m.module.into(),
|
||||||
// }),
|
// }),
|
||||||
// );
|
// );
|
||||||
m.item_map[m.module.module_id]
|
m.item_map[m.module.module_id].entries().for_each(|(name, res)| {
|
||||||
.entries()
|
f(name.clone(), res.def.map(Resolution::Def));
|
||||||
.for_each(|(name, res)| {
|
});
|
||||||
f(name.clone(), res.def.map(Resolution::Def));
|
|
||||||
});
|
|
||||||
m.item_map.extern_prelude.iter().for_each(|(name, def)| {
|
m.item_map.extern_prelude.iter().for_each(|(name, def)| {
|
||||||
f(name.clone(), PerNs::types(Resolution::Def(*def)));
|
f(name.clone(), PerNs::types(Resolution::Def(*def)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Scope::GenericParams(gp) => {
|
Scope::GenericParams(gp) => {
|
||||||
for param in &gp.params {
|
for param in &gp.params {
|
||||||
f(
|
f(param.name.clone(), PerNs::types(Resolution::GenericParam(param.idx)))
|
||||||
param.name.clone(),
|
|
||||||
PerNs::types(Resolution::GenericParam(param.idx)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Scope::ImplBlockScope(i) => {
|
Scope::ImplBlockScope(i) => {
|
||||||
f(
|
f(Name::self_type(), PerNs::types(Resolution::SelfType(i.clone())));
|
||||||
Name::self_type(),
|
|
||||||
PerNs::types(Resolution::SelfType(i.clone())),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Scope::ExprScope(e) => {
|
Scope::ExprScope(e) => {
|
||||||
e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
|
e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
|
||||||
f(
|
f(e.name().clone(), PerNs::values(Resolution::LocalBinding(e.pat())));
|
||||||
e.name().clone(),
|
|
||||||
PerNs::values(Resolution::LocalBinding(e.pat())),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,11 +65,7 @@ pub fn module_from_child_node(
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
child: &SyntaxNode,
|
child: &SyntaxNode,
|
||||||
) -> Option<Module> {
|
) -> Option<Module> {
|
||||||
if let Some(m) = child
|
if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
|
||||||
.ancestors()
|
|
||||||
.filter_map(ast::Module::cast)
|
|
||||||
.find(|it| !it.has_semi())
|
|
||||||
{
|
|
||||||
module_from_inline(db, file_id.into(), m)
|
module_from_inline(db, file_id.into(), m)
|
||||||
} else {
|
} else {
|
||||||
module_from_file_id(db, file_id.into())
|
module_from_file_id(db, file_id.into())
|
||||||
|
@ -82,14 +78,13 @@ fn module_from_source(
|
||||||
decl_id: Option<SourceFileItemId>,
|
decl_id: Option<SourceFileItemId>,
|
||||||
) -> Option<Module> {
|
) -> Option<Module> {
|
||||||
let source_root_id = db.file_source_root(file_id.as_original_file());
|
let source_root_id = db.file_source_root(file_id.as_original_file());
|
||||||
db.source_root_crates(source_root_id)
|
db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
|
||||||
.iter()
|
|krate| {
|
||||||
.map(|&crate_id| Crate { crate_id })
|
|
||||||
.find_map(|krate| {
|
|
||||||
let module_tree = db.module_tree(krate);
|
let module_tree = db.module_tree(krate);
|
||||||
let module_id = module_tree.find_module_by_source(file_id, decl_id)?;
|
let module_id = module_tree.find_module_by_source(file_id, decl_id)?;
|
||||||
Some(Module { krate, module_id })
|
Some(Module { krate, module_id })
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
|
pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
|
||||||
|
@ -116,9 +111,7 @@ pub fn function_from_module(
|
||||||
let (file_id, _) = module.definition_source(db);
|
let (file_id, _) = module.definition_source(db);
|
||||||
let file_id = file_id.into();
|
let file_id = file_id.into();
|
||||||
let ctx = LocationCtx::new(db, module, file_id);
|
let ctx = LocationCtx::new(db, module, file_id);
|
||||||
Function {
|
Function { id: ctx.to_def(fn_def) }
|
||||||
id: ctx.to_def(fn_def),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function_from_child_node(
|
pub fn function_from_child_node(
|
||||||
|
@ -138,18 +131,14 @@ pub fn struct_from_module(
|
||||||
let (file_id, _) = module.definition_source(db);
|
let (file_id, _) = module.definition_source(db);
|
||||||
let file_id = file_id.into();
|
let file_id = file_id.into();
|
||||||
let ctx = LocationCtx::new(db, module, file_id);
|
let ctx = LocationCtx::new(db, module, file_id);
|
||||||
Struct {
|
Struct { id: ctx.to_def(struct_def) }
|
||||||
id: ctx.to_def(struct_def),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
|
pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
|
||||||
let (file_id, _) = module.definition_source(db);
|
let (file_id, _) = module.definition_source(db);
|
||||||
let file_id = file_id.into();
|
let file_id = file_id.into();
|
||||||
let ctx = LocationCtx::new(db, module, file_id);
|
let ctx = LocationCtx::new(db, module, file_id);
|
||||||
Enum {
|
Enum { id: ctx.to_def(enum_def) }
|
||||||
id: ctx.to_def(enum_def),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_from_module(
|
pub fn trait_from_module(
|
||||||
|
@ -160,9 +149,7 @@ pub fn trait_from_module(
|
||||||
let (file_id, _) = module.definition_source(db);
|
let (file_id, _) = module.definition_source(db);
|
||||||
let file_id = file_id.into();
|
let file_id = file_id.into();
|
||||||
let ctx = LocationCtx::new(db, module, file_id);
|
let ctx = LocationCtx::new(db, module, file_id);
|
||||||
Trait {
|
Trait { id: ctx.to_def(trait_def) }
|
||||||
id: ctx.to_def(trait_def),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
|
pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, TextRange)> {
|
||||||
|
|
|
@ -305,10 +305,8 @@ impl Ty {
|
||||||
match type_ref {
|
match type_ref {
|
||||||
TypeRef::Never => Ty::Never,
|
TypeRef::Never => Ty::Never,
|
||||||
TypeRef::Tuple(inner) => {
|
TypeRef::Tuple(inner) => {
|
||||||
let inner_tys = inner
|
let inner_tys =
|
||||||
.iter()
|
inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
|
||||||
.map(|tr| Ty::from_hir(db, resolver, tr))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Ty::Tuple(inner_tys.into())
|
Ty::Tuple(inner_tys.into())
|
||||||
}
|
}
|
||||||
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
|
TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
|
||||||
|
@ -330,17 +328,11 @@ impl Ty {
|
||||||
}
|
}
|
||||||
TypeRef::Placeholder => Ty::Unknown,
|
TypeRef::Placeholder => Ty::Unknown,
|
||||||
TypeRef::Fn(params) => {
|
TypeRef::Fn(params) => {
|
||||||
let mut inner_tys = params
|
let mut inner_tys =
|
||||||
.iter()
|
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
|
||||||
.map(|tr| Ty::from_hir(db, resolver, tr))
|
let return_ty =
|
||||||
.collect::<Vec<_>>();
|
inner_tys.pop().expect("TypeRef::Fn should always have at least return type");
|
||||||
let return_ty = inner_tys
|
let sig = FnSig { input: inner_tys, output: return_ty };
|
||||||
.pop()
|
|
||||||
.expect("TypeRef::Fn should always have at least return type");
|
|
||||||
let sig = FnSig {
|
|
||||||
input: inner_tys,
|
|
||||||
output: return_ty,
|
|
||||||
};
|
|
||||||
Ty::FnPtr(Arc::new(sig))
|
Ty::FnPtr(Arc::new(sig))
|
||||||
}
|
}
|
||||||
TypeRef::Error => Ty::Unknown,
|
TypeRef::Error => Ty::Unknown,
|
||||||
|
@ -407,10 +399,7 @@ impl Ty {
|
||||||
resolved: TypableDef,
|
resolved: TypableDef,
|
||||||
) -> Substs {
|
) -> Substs {
|
||||||
let mut substs = Vec::new();
|
let mut substs = Vec::new();
|
||||||
let last = path
|
let last = path.segments.last().expect("path should have at least one segment");
|
||||||
.segments
|
|
||||||
.last()
|
|
||||||
.expect("path should have at least one segment");
|
|
||||||
let (def_generics, segment) = match resolved {
|
let (def_generics, segment) = match resolved {
|
||||||
TypableDef::Function(func) => (func.generic_params(db), last),
|
TypableDef::Function(func) => (func.generic_params(db), last),
|
||||||
TypableDef::Struct(s) => (s.generic_params(db), last),
|
TypableDef::Struct(s) => (s.generic_params(db), last),
|
||||||
|
@ -447,11 +436,8 @@ impl Ty {
|
||||||
}
|
}
|
||||||
// add placeholders for args that were not provided
|
// add placeholders for args that were not provided
|
||||||
// TODO: handle defaults
|
// TODO: handle defaults
|
||||||
let supplied_params = segment
|
let supplied_params =
|
||||||
.args_and_bindings
|
segment.args_and_bindings.as_ref().map(|ga| ga.args.len()).unwrap_or(0);
|
||||||
.as_ref()
|
|
||||||
.map(|ga| ga.args.len())
|
|
||||||
.unwrap_or(0);
|
|
||||||
for _ in supplied_params..def_generics.params.len() {
|
for _ in supplied_params..def_generics.params.len() {
|
||||||
substs.push(Ty::Unknown);
|
substs.push(Ty::Unknown);
|
||||||
}
|
}
|
||||||
|
@ -531,17 +517,8 @@ impl Ty {
|
||||||
/// `Option<u32>` afterwards.)
|
/// `Option<u32>` afterwards.)
|
||||||
pub fn apply_substs(self, substs: Substs) -> Ty {
|
pub fn apply_substs(self, substs: Substs) -> Ty {
|
||||||
match self {
|
match self {
|
||||||
Ty::Adt { def_id, name, .. } => Ty::Adt {
|
Ty::Adt { def_id, name, .. } => Ty::Adt { def_id, name, substs },
|
||||||
def_id,
|
Ty::FnDef { def, name, sig, .. } => Ty::FnDef { def, name, sig, substs },
|
||||||
name,
|
|
||||||
substs,
|
|
||||||
},
|
|
||||||
Ty::FnDef { def, name, sig, .. } => Ty::FnDef {
|
|
||||||
def,
|
|
||||||
name,
|
|
||||||
sig,
|
|
||||||
substs,
|
|
||||||
},
|
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,42 +568,25 @@ impl fmt::Display for Ty {
|
||||||
if ts.len() == 1 {
|
if ts.len() == 1 {
|
||||||
write!(f, "({},)", ts[0])
|
write!(f, "({},)", ts[0])
|
||||||
} else {
|
} else {
|
||||||
join(ts.iter())
|
join(ts.iter()).surround_with("(", ")").separator(", ").to_fmt(f)
|
||||||
.surround_with("(", ")")
|
|
||||||
.separator(", ")
|
|
||||||
.to_fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ty::FnPtr(sig) => {
|
Ty::FnPtr(sig) => {
|
||||||
join(sig.input.iter())
|
join(sig.input.iter()).surround_with("fn(", ")").separator(", ").to_fmt(f)?;
|
||||||
.surround_with("fn(", ")")
|
|
||||||
.separator(", ")
|
|
||||||
.to_fmt(f)?;
|
|
||||||
write!(f, " -> {}", sig.output)
|
write!(f, " -> {}", sig.output)
|
||||||
}
|
}
|
||||||
Ty::FnDef {
|
Ty::FnDef { name, substs, sig, .. } => {
|
||||||
name, substs, sig, ..
|
|
||||||
} => {
|
|
||||||
write!(f, "fn {}", name)?;
|
write!(f, "fn {}", name)?;
|
||||||
if substs.0.len() > 0 {
|
if substs.0.len() > 0 {
|
||||||
join(substs.0.iter())
|
join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?;
|
||||||
.surround_with("<", ">")
|
|
||||||
.separator(", ")
|
|
||||||
.to_fmt(f)?;
|
|
||||||
}
|
}
|
||||||
join(sig.input.iter())
|
join(sig.input.iter()).surround_with("(", ")").separator(", ").to_fmt(f)?;
|
||||||
.surround_with("(", ")")
|
|
||||||
.separator(", ")
|
|
||||||
.to_fmt(f)?;
|
|
||||||
write!(f, " -> {}", sig.output)
|
write!(f, " -> {}", sig.output)
|
||||||
}
|
}
|
||||||
Ty::Adt { name, substs, .. } => {
|
Ty::Adt { name, substs, .. } => {
|
||||||
write!(f, "{}", name)?;
|
write!(f, "{}", name)?;
|
||||||
if substs.0.len() > 0 {
|
if substs.0.len() > 0 {
|
||||||
join(substs.0.iter())
|
join(substs.0.iter()).surround_with("<", ">").separator(", ").to_fmt(f)?;
|
||||||
.surround_with("<", ">")
|
|
||||||
.separator(", ")
|
|
||||||
.to_fmt(f)?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -646,31 +606,16 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
|
||||||
let resolver = def.resolver(db);
|
let resolver = def.resolver(db);
|
||||||
let generics = def.generic_params(db);
|
let generics = def.generic_params(db);
|
||||||
let name = def.name(db);
|
let name = def.name(db);
|
||||||
let input = signature
|
let input =
|
||||||
.params()
|
signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
|
||||||
.iter()
|
|
||||||
.map(|tr| Ty::from_hir(db, &resolver, tr))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let output = Ty::from_hir(db, &resolver, signature.ret_type());
|
let output = Ty::from_hir(db, &resolver, signature.ret_type());
|
||||||
let sig = Arc::new(FnSig { input, output });
|
let sig = Arc::new(FnSig { input, output });
|
||||||
let substs = make_substs(&generics);
|
let substs = make_substs(&generics);
|
||||||
Ty::FnDef {
|
Ty::FnDef { def, sig, name, substs }
|
||||||
def,
|
|
||||||
sig,
|
|
||||||
name,
|
|
||||||
substs,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_substs(generics: &GenericParams) -> Substs {
|
fn make_substs(generics: &GenericParams) -> Substs {
|
||||||
Substs(
|
Substs(generics.params.iter().map(|_p| Ty::Unknown).collect::<Vec<_>>().into())
|
||||||
generics
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.map(|_p| Ty::Unknown)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
|
fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
|
||||||
|
@ -935,11 +880,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
|
fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool {
|
||||||
substs1
|
substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify(t1, t2))
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.zip(substs2.0.iter())
|
|
||||||
.all(|(t1, t2)| self.unify(t1, t2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
||||||
|
@ -961,25 +902,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
},
|
},
|
||||||
(Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
|
(Ty::Bool, _) | (Ty::Str, _) | (Ty::Never, _) | (Ty::Char, _) => ty1 == ty2,
|
||||||
(
|
(
|
||||||
Ty::Adt {
|
Ty::Adt { def_id: def_id1, substs: substs1, .. },
|
||||||
def_id: def_id1,
|
Ty::Adt { def_id: def_id2, substs: substs2, .. },
|
||||||
substs: substs1,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
Ty::Adt {
|
|
||||||
def_id: def_id2,
|
|
||||||
substs: substs2,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
|
) if def_id1 == def_id2 => self.unify_substs(substs1, substs2),
|
||||||
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
|
(Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2),
|
||||||
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
|
(Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2),
|
||||||
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
|
(Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2),
|
||||||
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
|
(Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true,
|
||||||
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => ts1
|
(Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => {
|
||||||
.iter()
|
ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify(t1, t2))
|
||||||
.zip(ts2.iter())
|
}
|
||||||
.all(|(t1, t2)| self.unify(t1, t2)),
|
|
||||||
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
||||||
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
||||||
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
|
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
|
||||||
|
@ -994,8 +926,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
| (Ty::Infer(InferTy::FloatVar(tv)), other)
|
| (Ty::Infer(InferTy::FloatVar(tv)), other)
|
||||||
| (other, Ty::Infer(InferTy::FloatVar(tv))) => {
|
| (other, Ty::Infer(InferTy::FloatVar(tv))) => {
|
||||||
// the type var is unknown since we tried to resolve it
|
// the type var is unknown since we tried to resolve it
|
||||||
self.var_unification_table
|
self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
|
||||||
.union_value(*tv, TypeVarValue::Known(other.clone()));
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -1003,21 +934,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_type_var(&mut self) -> Ty {
|
fn new_type_var(&mut self) -> Ty {
|
||||||
Ty::Infer(InferTy::TypeVar(
|
Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
|
||||||
self.var_unification_table.new_key(TypeVarValue::Unknown),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_integer_var(&mut self) -> Ty {
|
fn new_integer_var(&mut self) -> Ty {
|
||||||
Ty::Infer(InferTy::IntVar(
|
Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
|
||||||
self.var_unification_table.new_key(TypeVarValue::Unknown),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_float_var(&mut self) -> Ty {
|
fn new_float_var(&mut self) -> Ty {
|
||||||
Ty::Infer(InferTy::FloatVar(
|
Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
|
||||||
self.var_unification_table.new_key(TypeVarValue::Unknown),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
|
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
|
||||||
|
@ -1207,9 +1132,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
for subpat in subpats {
|
for subpat in subpats {
|
||||||
let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
|
let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
|
||||||
let expected_ty = matching_field
|
let expected_ty =
|
||||||
.map_or(Ty::Unknown, |field| field.ty(self.db))
|
matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
|
||||||
.subst(&substs);
|
|
||||||
self.infer_pat(subpat.pat, &expected_ty);
|
self.infer_pat(subpat.pat, &expected_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1249,25 +1173,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let subty = self.infer_pat(*pat, expectation);
|
let subty = self.infer_pat(*pat, expectation);
|
||||||
Ty::Ref(subty.into(), *mutability)
|
Ty::Ref(subty.into(), *mutability)
|
||||||
}
|
}
|
||||||
Pat::TupleStruct {
|
Pat::TupleStruct { path: ref p, args: ref subpats } => {
|
||||||
path: ref p,
|
self.infer_tuple_struct_pat(p.as_ref(), subpats, expected)
|
||||||
args: ref subpats,
|
}
|
||||||
} => self.infer_tuple_struct_pat(p.as_ref(), subpats, expected),
|
Pat::Struct { path: ref p, args: ref fields } => {
|
||||||
Pat::Struct {
|
self.infer_struct_pat(p.as_ref(), fields, expected)
|
||||||
path: ref p,
|
}
|
||||||
args: ref fields,
|
|
||||||
} => self.infer_struct_pat(p.as_ref(), fields, expected),
|
|
||||||
Pat::Path(path) => {
|
Pat::Path(path) => {
|
||||||
// TODO use correct resolver for the surrounding expression
|
// TODO use correct resolver for the surrounding expression
|
||||||
let resolver = self.resolver.clone();
|
let resolver = self.resolver.clone();
|
||||||
self.infer_path_expr(&resolver, &path)
|
self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown)
|
||||||
.unwrap_or(Ty::Unknown)
|
|
||||||
}
|
}
|
||||||
Pat::Bind {
|
Pat::Bind { mode, name: _name, subpat } => {
|
||||||
mode,
|
|
||||||
name: _name,
|
|
||||||
subpat,
|
|
||||||
} => {
|
|
||||||
let subty = if let Some(subpat) = subpat {
|
let subty = if let Some(subpat) = subpat {
|
||||||
self.infer_pat(*subpat, expected)
|
self.infer_pat(*subpat, expected)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1294,11 +1211,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
||||||
let ty = match &body[tgt_expr] {
|
let ty = match &body[tgt_expr] {
|
||||||
Expr::Missing => Ty::Unknown,
|
Expr::Missing => Ty::Unknown,
|
||||||
Expr::If {
|
Expr::If { condition, then_branch, else_branch } => {
|
||||||
condition,
|
|
||||||
then_branch,
|
|
||||||
else_branch,
|
|
||||||
} => {
|
|
||||||
// if let is desugared to match, so this is always simple if
|
// if let is desugared to match, so this is always simple if
|
||||||
self.infer_expr(*condition, &Expectation::has_type(Ty::Bool));
|
self.infer_expr(*condition, &Expectation::has_type(Ty::Bool));
|
||||||
let then_ty = self.infer_expr(*then_branch, expected);
|
let then_ty = self.infer_expr(*then_branch, expected);
|
||||||
|
@ -1325,21 +1238,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||||
Ty::unit()
|
Ty::unit()
|
||||||
}
|
}
|
||||||
Expr::For {
|
Expr::For { iterable, body, pat } => {
|
||||||
iterable,
|
|
||||||
body,
|
|
||||||
pat,
|
|
||||||
} => {
|
|
||||||
let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
|
let _iterable_ty = self.infer_expr(*iterable, &Expectation::none());
|
||||||
self.infer_pat(*pat, &Ty::Unknown);
|
self.infer_pat(*pat, &Ty::Unknown);
|
||||||
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
|
||||||
Ty::unit()
|
Ty::unit()
|
||||||
}
|
}
|
||||||
Expr::Lambda {
|
Expr::Lambda { body, args, arg_types } => {
|
||||||
body,
|
|
||||||
args,
|
|
||||||
arg_types,
|
|
||||||
} => {
|
|
||||||
assert_eq!(args.len(), arg_types.len());
|
assert_eq!(args.len(), arg_types.len());
|
||||||
|
|
||||||
for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
|
for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
|
||||||
|
@ -1362,11 +1267,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()),
|
Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()),
|
||||||
Ty::FnDef { substs, sig, .. } => {
|
Ty::FnDef { substs, sig, .. } => {
|
||||||
let ret_ty = sig.output.clone().subst(&substs);
|
let ret_ty = sig.output.clone().subst(&substs);
|
||||||
let param_tys = sig
|
let param_tys =
|
||||||
.input
|
sig.input.iter().map(|ty| ty.clone().subst(&substs)).collect();
|
||||||
.iter()
|
|
||||||
.map(|ty| ty.clone().subst(&substs))
|
|
||||||
.collect();
|
|
||||||
(param_tys, ret_ty)
|
(param_tys, ret_ty)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1381,11 +1283,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
ret_ty
|
ret_ty
|
||||||
}
|
}
|
||||||
Expr::MethodCall {
|
Expr::MethodCall { receiver, args, method_name } => {
|
||||||
receiver,
|
|
||||||
args,
|
|
||||||
method_name,
|
|
||||||
} => {
|
|
||||||
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
||||||
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
|
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
|
||||||
let method_ty = match resolved {
|
let method_ty = match resolved {
|
||||||
|
@ -1399,11 +1297,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
||||||
Ty::FnPtr(sig) => {
|
Ty::FnPtr(sig) => {
|
||||||
if !sig.input.is_empty() {
|
if !sig.input.is_empty() {
|
||||||
(
|
(sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone())
|
||||||
sig.input[0].clone(),
|
|
||||||
sig.input[1..].to_vec(),
|
|
||||||
sig.output.clone(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(Ty::Unknown, Vec::new(), sig.output.clone())
|
(Ty::Unknown, Vec::new(), sig.output.clone())
|
||||||
}
|
}
|
||||||
|
@ -1469,11 +1363,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
Ty::Never
|
Ty::Never
|
||||||
}
|
}
|
||||||
Expr::StructLit {
|
Expr::StructLit { path, fields, spread } => {
|
||||||
path,
|
|
||||||
fields,
|
|
||||||
spread,
|
|
||||||
} => {
|
|
||||||
let (ty, def_id) = self.resolve_variant(path.as_ref());
|
let (ty, def_id) = self.resolve_variant(path.as_ref());
|
||||||
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
let substs = ty.substs().unwrap_or_else(Substs::empty);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
|
@ -1497,14 +1387,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let i = name.to_string().parse::<usize>().ok();
|
let i = name.to_string().parse::<usize>().ok();
|
||||||
i.and_then(|i| fields.get(i).cloned())
|
i.and_then(|i| fields.get(i).cloned())
|
||||||
}
|
}
|
||||||
Ty::Adt {
|
Ty::Adt { def_id: AdtDef::Struct(s), ref substs, .. } => {
|
||||||
def_id: AdtDef::Struct(s),
|
s.field(self.db, name).map(|field| {
|
||||||
ref substs,
|
self.write_field_resolution(tgt_expr, field);
|
||||||
..
|
field.ty(self.db).subst(substs)
|
||||||
} => s.field(self.db, name).map(|field| {
|
})
|
||||||
self.write_field_resolution(tgt_expr, field);
|
}
|
||||||
field.ty(self.db).subst(substs)
|
|
||||||
}),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.unwrap_or(Ty::Unknown);
|
.unwrap_or(Ty::Unknown);
|
||||||
|
@ -1635,15 +1523,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Let {
|
Statement::Let { pat, type_ref, initializer } => {
|
||||||
pat,
|
let decl_ty =
|
||||||
type_ref,
|
type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown);
|
||||||
initializer,
|
|
||||||
} => {
|
|
||||||
let decl_ty = type_ref
|
|
||||||
.as_ref()
|
|
||||||
.map(|tr| self.make_ty(tr))
|
|
||||||
.unwrap_or(Ty::Unknown);
|
|
||||||
let decl_ty = self.insert_type_vars(decl_ty);
|
let decl_ty = self.insert_type_vars(decl_ty);
|
||||||
let ty = if let Some(expr) = initializer {
|
let ty = if let Some(expr) = initializer {
|
||||||
let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty));
|
let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty));
|
||||||
|
@ -1659,11 +1541,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ty = if let Some(expr) = tail {
|
let ty = if let Some(expr) = tail { self.infer_expr(expr, expected) } else { Ty::unit() };
|
||||||
self.infer_expr(expr, expected)
|
|
||||||
} else {
|
|
||||||
Ty::unit()
|
|
||||||
};
|
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1678,10 +1556,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_body(&mut self) {
|
fn infer_body(&mut self) {
|
||||||
self.infer_expr(
|
self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone()));
|
||||||
self.body.body_expr(),
|
|
||||||
&Expectation::has_type(self.return_ty.clone()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,18 +46,13 @@ impl CrateImplBlocks {
|
||||||
ty: &Ty,
|
ty: &Ty,
|
||||||
) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
|
) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
|
||||||
let fingerprint = TyFingerprint::for_impl(ty);
|
let fingerprint = TyFingerprint::for_impl(ty);
|
||||||
fingerprint
|
fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
|
||||||
.and_then(|f| self.impls.get(&f))
|
move |(module_id, impl_id)| {
|
||||||
.into_iter()
|
let module = Module { krate: self.krate, module_id: *module_id };
|
||||||
.flat_map(|i| i.iter())
|
|
||||||
.map(move |(module_id, impl_id)| {
|
|
||||||
let module = Module {
|
|
||||||
krate: self.krate,
|
|
||||||
module_id: *module_id,
|
|
||||||
};
|
|
||||||
let module_impl_blocks = db.impls_in_module(module);
|
let module_impl_blocks = db.impls_in_module(module);
|
||||||
(module, ImplBlock::from_id(module_impl_blocks, *impl_id))
|
(module, ImplBlock::from_id(module_impl_blocks, *impl_id))
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_impl_blocks_for_trait<'a>(
|
pub fn lookup_impl_blocks_for_trait<'a>(
|
||||||
|
@ -66,18 +61,13 @@ impl CrateImplBlocks {
|
||||||
tr: &Trait,
|
tr: &Trait,
|
||||||
) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
|
) -> impl Iterator<Item = (Module, ImplBlock)> + 'a {
|
||||||
let id = tr.id;
|
let id = tr.id;
|
||||||
self.impls_by_trait
|
self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
|
||||||
.get(&id)
|
move |(module_id, impl_id)| {
|
||||||
.into_iter()
|
let module = Module { krate: self.krate, module_id: *module_id };
|
||||||
.flat_map(|i| i.iter())
|
|
||||||
.map(move |(module_id, impl_id)| {
|
|
||||||
let module = Module {
|
|
||||||
krate: self.krate,
|
|
||||||
module_id: *module_id,
|
|
||||||
};
|
|
||||||
let module_impl_blocks = db.impls_in_module(module);
|
let module_impl_blocks = db.impls_in_module(module);
|
||||||
(module, ImplBlock::from_id(module_impl_blocks, *impl_id))
|
(module, ImplBlock::from_id(module_impl_blocks, *impl_id))
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
|
fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) {
|
||||||
|
|
|
@ -634,11 +634,7 @@ fn infer(content: &str) -> String {
|
||||||
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
||||||
let source_file = db.parse(file_id);
|
let source_file = db.parse(file_id);
|
||||||
let mut acc = String::new();
|
let mut acc = String::new();
|
||||||
for fn_def in source_file
|
for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) {
|
||||||
.syntax()
|
|
||||||
.descendants()
|
|
||||||
.filter_map(ast::FnDef::cast)
|
|
||||||
{
|
|
||||||
let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap();
|
let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap();
|
||||||
let inference_result = func.infer(&db);
|
let inference_result = func.infer(&db);
|
||||||
let body_syntax_mapping = func.body_syntax_mapping(&db);
|
let body_syntax_mapping = func.body_syntax_mapping(&db);
|
||||||
|
@ -725,8 +721,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
|
||||||
"
|
"
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
db.query_mut(ra_db::FileTextQuery)
|
db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text));
|
||||||
.set(pos.file_id, Arc::new(new_text));
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let events = db.log_executed(|| {
|
let events = db.log_executed(|| {
|
||||||
|
|
|
@ -62,11 +62,9 @@ impl TypeRef {
|
||||||
ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
|
ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
|
||||||
TupleType(inner) => TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()),
|
TupleType(inner) => TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()),
|
||||||
NeverType(..) => TypeRef::Never,
|
NeverType(..) => TypeRef::Never,
|
||||||
PathType(inner) => inner
|
PathType(inner) => {
|
||||||
.path()
|
inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error)
|
||||||
.and_then(Path::from_ast)
|
}
|
||||||
.map(TypeRef::Path)
|
|
||||||
.unwrap_or(TypeRef::Error),
|
|
||||||
PointerType(inner) => {
|
PointerType(inner) => {
|
||||||
let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
|
let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
|
||||||
let mutability = Mutability::from_mutable(inner.is_mut());
|
let mutability = Mutability::from_mutable(inner.is_mut());
|
||||||
|
@ -83,10 +81,7 @@ impl TypeRef {
|
||||||
FnPointerType(inner) => {
|
FnPointerType(inner) => {
|
||||||
let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref()));
|
let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref()));
|
||||||
let mut params = if let Some(pl) = inner.param_list() {
|
let mut params = if let Some(pl) = inner.param_list() {
|
||||||
pl.params()
|
pl.params().map(|p| p.type_ref()).map(TypeRef::from_ast_opt).collect()
|
||||||
.map(|p| p.type_ref())
|
|
||||||
.map(TypeRef::from_ast_opt)
|
|
||||||
.collect()
|
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,10 +7,7 @@ pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<SourceChange>
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(label, action)| {
|
.map(|(label, action)| {
|
||||||
let file_id = frange.file_id;
|
let file_id = frange.file_id;
|
||||||
let file_edit = SourceFileEdit {
|
let file_edit = SourceFileEdit { file_id, edit: action.edit };
|
||||||
file_id,
|
|
||||||
edit: action.edit,
|
|
||||||
};
|
|
||||||
SourceChange {
|
SourceChange {
|
||||||
label: label.label,
|
label: label.label,
|
||||||
source_file_edits: vec![file_edit],
|
source_file_edits: vec![file_edit],
|
||||||
|
|
|
@ -21,9 +21,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
|
||||||
|
|
||||||
// Resolve the function's NameRef (NOTE: this isn't entirely accurate).
|
// Resolve the function's NameRef (NOTE: this isn't entirely accurate).
|
||||||
let file_symbols = crate::symbol_index::index_resolve(db, name_ref);
|
let file_symbols = crate::symbol_index::index_resolve(db, name_ref);
|
||||||
let symbol = file_symbols
|
let symbol = file_symbols.into_iter().find(|it| it.ptr.kind() == FN_DEF)?;
|
||||||
.into_iter()
|
|
||||||
.find(|it| it.ptr.kind() == FN_DEF)?;
|
|
||||||
let fn_file = db.parse(symbol.file_id);
|
let fn_file = db.parse(symbol.file_id);
|
||||||
let fn_def = symbol.ptr.to_node(&fn_file);
|
let fn_def = symbol.ptr.to_node(&fn_file);
|
||||||
let fn_def = ast::FnDef::cast(fn_def).unwrap();
|
let fn_def = ast::FnDef::cast(fn_def).unwrap();
|
||||||
|
@ -53,13 +51,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
|
||||||
let start = arg_list_range.start();
|
let start = arg_list_range.start();
|
||||||
|
|
||||||
let range_search = TextRange::from_to(start, position.offset);
|
let range_search = TextRange::from_to(start, position.offset);
|
||||||
let mut commas: usize = arg_list
|
let mut commas: usize =
|
||||||
.syntax()
|
arg_list.syntax().text().slice(range_search).to_string().matches(',').count();
|
||||||
.text()
|
|
||||||
.slice(range_search)
|
|
||||||
.to_string()
|
|
||||||
.matches(',')
|
|
||||||
.count();
|
|
||||||
|
|
||||||
// If we have a method call eat the first param since it's just self.
|
// If we have a method call eat the first param since it's just self.
|
||||||
if has_self {
|
if has_self {
|
||||||
|
@ -96,11 +89,9 @@ impl<'a> FnCallNode<'a> {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
FnCallNode::MethodCallExpr(call_expr) => call_expr
|
FnCallNode::MethodCallExpr(call_expr) => {
|
||||||
.syntax()
|
call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0)
|
||||||
.children()
|
}
|
||||||
.filter_map(ast::NameRef::cast)
|
|
||||||
.nth(0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,12 +108,7 @@ impl CallInfo {
|
||||||
let label = crate::completion::function_label(node)?;
|
let label = crate::completion::function_label(node)?;
|
||||||
let doc = function.docs(db);
|
let doc = function.docs(db);
|
||||||
|
|
||||||
Some(CallInfo {
|
Some(CallInfo { parameters: param_list(node), label, doc, active_parameter: None })
|
||||||
parameters: param_list(node),
|
|
||||||
label,
|
|
||||||
doc,
|
|
||||||
active_parameter: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,10 +122,7 @@ fn param_list(node: &ast::FnDef) -> Vec<String> {
|
||||||
// Maybe use param.pat here? See if we can just extract the name?
|
// Maybe use param.pat here? See if we can just extract the name?
|
||||||
//res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
|
//res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
|
||||||
res.extend(
|
res.extend(
|
||||||
param_list
|
param_list.params().filter_map(|p| p.pat()).map(|pat| pat.syntax().text().to_string()),
|
||||||
.params()
|
|
||||||
.filter_map(|p| p.pat())
|
|
||||||
.map(|pat| pat.syntax().text().to_string()),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
|
@ -378,10 +361,7 @@ pub fn foo() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(info.parameters, vec!["&mut self".to_string(), "ctx".to_string()]);
|
||||||
info.parameters,
|
|
||||||
vec!["&mut self".to_string(), "ctx".to_string()]
|
|
||||||
);
|
|
||||||
assert_eq!(info.active_parameter, Some(1));
|
assert_eq!(info.active_parameter, Some(1));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
info.doc.map(|it| it.into()),
|
info.doc.map(|it| it.into()),
|
||||||
|
|
|
@ -65,16 +65,8 @@ impl AnalysisChange {
|
||||||
path: RelativePathBuf,
|
path: RelativePathBuf,
|
||||||
text: Arc<String>,
|
text: Arc<String>,
|
||||||
) {
|
) {
|
||||||
let file = AddFile {
|
let file = AddFile { file_id, path, text };
|
||||||
file_id,
|
self.roots_changed.entry(root_id).or_default().added.push(file);
|
||||||
path,
|
|
||||||
text,
|
|
||||||
};
|
|
||||||
self.roots_changed
|
|
||||||
.entry(root_id)
|
|
||||||
.or_default()
|
|
||||||
.added
|
|
||||||
.push(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
|
pub fn change_file(&mut self, file_id: FileId, new_text: Arc<String>) {
|
||||||
|
@ -83,11 +75,7 @@ impl AnalysisChange {
|
||||||
|
|
||||||
pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
|
pub fn remove_file(&mut self, root_id: SourceRootId, file_id: FileId, path: RelativePathBuf) {
|
||||||
let file = RemoveFile { file_id, path };
|
let file = RemoveFile { file_id, path };
|
||||||
self.roots_changed
|
self.roots_changed.entry(root_id).or_default().removed.push(file);
|
||||||
.entry(root_id)
|
|
||||||
.or_default()
|
|
||||||
.removed
|
|
||||||
.push(file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_library(&mut self, data: LibraryData) {
|
pub fn add_library(&mut self, data: LibraryData) {
|
||||||
|
@ -155,17 +143,9 @@ impl LibraryData {
|
||||||
let mut root_change = RootChange::default();
|
let mut root_change = RootChange::default();
|
||||||
root_change.added = files
|
root_change.added = files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(file_id, path, text)| AddFile {
|
.map(|(file_id, path, text)| AddFile { file_id, path, text })
|
||||||
file_id,
|
|
||||||
path,
|
|
||||||
text,
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
LibraryData {
|
LibraryData { root_id, root_change, symbol_index }
|
||||||
root_id,
|
|
||||||
root_change,
|
|
||||||
symbol_index,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +206,7 @@ impl RootDatabase {
|
||||||
self.last_gc_check = time::Instant::now();
|
self.last_gc_check = time::Instant::now();
|
||||||
let retained_trees = syntax_tree_stats(self).retained;
|
let retained_trees = syntax_tree_stats(self).retained;
|
||||||
if retained_trees > 100 {
|
if retained_trees > 100 {
|
||||||
log::info!(
|
log::info!("automatic garbadge collection, {} retained trees", retained_trees);
|
||||||
"automatic garbadge collection, {} retained trees",
|
|
||||||
retained_trees
|
|
||||||
);
|
|
||||||
self.collect_garbage();
|
self.collect_garbage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,9 +215,7 @@ impl RootDatabase {
|
||||||
pub(crate) fn collect_garbage(&mut self) {
|
pub(crate) fn collect_garbage(&mut self) {
|
||||||
self.last_gc = time::Instant::now();
|
self.last_gc = time::Instant::now();
|
||||||
|
|
||||||
let sweep = SweepStrategy::default()
|
let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
|
||||||
.discard_values()
|
|
||||||
.sweep_all_revisions();
|
|
||||||
|
|
||||||
self.query(ra_db::ParseQuery).sweep(sweep);
|
self.query(ra_db::ParseQuery).sweep(sweep);
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
|
fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
|
||||||
for receiver in receiver.autoderef(ctx.db) {
|
for receiver in receiver.autoderef(ctx.db) {
|
||||||
match receiver {
|
match receiver {
|
||||||
Ty::Adt {
|
Ty::Adt { def_id, ref substs, .. } => {
|
||||||
def_id, ref substs, ..
|
|
||||||
} => {
|
|
||||||
match def_id {
|
match def_id {
|
||||||
AdtDef::Struct(s) => {
|
AdtDef::Struct(s) => {
|
||||||
for field in s.fields(ctx.db) {
|
for field in s.fields(ctx.db) {
|
||||||
|
|
|
@ -43,13 +43,12 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
node: &'a N,
|
node: &'a N,
|
||||||
params: &mut FxHashMap<String, (u32, &'a ast::Param)>,
|
params: &mut FxHashMap<String, (u32, &'a ast::Param)>,
|
||||||
) {
|
) {
|
||||||
node.functions()
|
node.functions().filter_map(|it| it.param_list()).flat_map(|it| it.params()).for_each(
|
||||||
.filter_map(|it| it.param_list())
|
|param| {
|
||||||
.flat_map(|it| it.params())
|
|
||||||
.for_each(|param| {
|
|
||||||
let text = param.syntax().text().to_string();
|
let text = param.syntax().text().to_string();
|
||||||
params.entry(text).or_insert((0, param)).0 += 1;
|
params.entry(text).or_insert((0, param)).0 += 1;
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,14 +31,10 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
hir::ModuleDef::Enum(e) => {
|
hir::ModuleDef::Enum(e) => {
|
||||||
e.variants(ctx.db).into_iter().for_each(|variant| {
|
e.variants(ctx.db).into_iter().for_each(|variant| {
|
||||||
if let Some(name) = variant.name(ctx.db) {
|
if let Some(name) = variant.name(ctx.db) {
|
||||||
let detail_types = variant
|
let detail_types =
|
||||||
.fields(ctx.db)
|
variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db));
|
||||||
.into_iter()
|
let detail =
|
||||||
.map(|field| field.ty(ctx.db));
|
join(detail_types).separator(", ").surround_with("(", ")").to_string();
|
||||||
let detail = join(detail_types)
|
|
||||||
.separator(", ")
|
|
||||||
.surround_with("(", ")")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
CompletionItem::new(
|
CompletionItem::new(
|
||||||
CompletionKind::Reference,
|
CompletionKind::Reference,
|
||||||
|
|
|
@ -17,11 +17,7 @@ use ra_text_edit::TextEditBuilder;
|
||||||
|
|
||||||
fn postfix_snippet(ctx: &CompletionContext, label: &str, snippet: &str) -> Builder {
|
fn postfix_snippet(ctx: &CompletionContext, label: &str, snippet: &str) -> Builder {
|
||||||
let replace_range = ctx.source_range();
|
let replace_range = ctx.source_range();
|
||||||
let receiver_range = ctx
|
let receiver_range = ctx.dot_receiver.expect("no receiver available").syntax().range();
|
||||||
.dot_receiver
|
|
||||||
.expect("no receiver available")
|
|
||||||
.syntax()
|
|
||||||
.range();
|
|
||||||
let delete_range = TextRange::from_to(receiver_range.start(), replace_range.start());
|
let delete_range = TextRange::from_to(receiver_range.start(), replace_range.start());
|
||||||
let mut builder = TextEditBuilder::default();
|
let mut builder = TextEditBuilder::default();
|
||||||
builder.delete(delete_range);
|
builder.delete(delete_range);
|
||||||
|
|
|
@ -7,13 +7,9 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
let names = ctx.resolver.all_names();
|
let names = ctx.resolver.all_names();
|
||||||
|
|
||||||
names.into_iter().for_each(|(name, res)| {
|
names.into_iter().for_each(|(name, res)| {
|
||||||
CompletionItem::new(
|
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
|
||||||
CompletionKind::Reference,
|
.from_resolution(ctx, &res)
|
||||||
ctx.source_range(),
|
.add_to(acc)
|
||||||
name.to_string(),
|
|
||||||
)
|
|
||||||
.from_resolution(ctx, &res)
|
|
||||||
.add_to(acc)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,12 +108,8 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
fn classify_name_ref(&mut self, original_file: &'a SourceFile, name_ref: &ast::NameRef) {
|
fn classify_name_ref(&mut self, original_file: &'a SourceFile, name_ref: &ast::NameRef) {
|
||||||
let name_range = name_ref.syntax().range();
|
let name_range = name_ref.syntax().range();
|
||||||
let top_node = name_ref
|
let top_node =
|
||||||
.syntax()
|
name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap();
|
||||||
.ancestors()
|
|
||||||
.take_while(|it| it.range() == name_range)
|
|
||||||
.last()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
match top_node.parent().map(|it| it.kind()) {
|
match top_node.parent().map(|it| it.kind()) {
|
||||||
Some(SOURCE_FILE) | Some(ITEM_LIST) => {
|
Some(SOURCE_FILE) | Some(ITEM_LIST) => {
|
||||||
|
|
|
@ -105,10 +105,7 @@ impl CompletionItem {
|
||||||
}
|
}
|
||||||
/// What string is used for filtering.
|
/// What string is used for filtering.
|
||||||
pub fn lookup(&self) -> &str {
|
pub fn lookup(&self) -> &str {
|
||||||
self.lookup
|
self.lookup.as_ref().map(|it| it.as_str()).unwrap_or_else(|| self.label())
|
||||||
.as_ref()
|
|
||||||
.map(|it| it.as_str())
|
|
||||||
.unwrap_or_else(|| self.label())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_text_format(&self) -> InsertTextFormat {
|
pub fn insert_text_format(&self) -> InsertTextFormat {
|
||||||
|
@ -214,10 +211,7 @@ impl Builder {
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
use hir::ModuleDef::*;
|
use hir::ModuleDef::*;
|
||||||
|
|
||||||
let def = resolution
|
let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
|
||||||
.as_ref()
|
|
||||||
.take_types()
|
|
||||||
.or_else(|| resolution.as_ref().take_values());
|
|
||||||
let def = match def {
|
let def = match def {
|
||||||
None => return self,
|
None => return self,
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
|
@ -323,10 +317,8 @@ pub(crate) fn check_completion(test_name: &str, code: &str, kind: CompletionKind
|
||||||
};
|
};
|
||||||
let completions = completions(&analysis.db, position).unwrap();
|
let completions = completions(&analysis.db, position).unwrap();
|
||||||
let completion_items: Vec<CompletionItem> = completions.into();
|
let completion_items: Vec<CompletionItem> = completions.into();
|
||||||
let mut kind_completions: Vec<CompletionItem> = completion_items
|
let mut kind_completions: Vec<CompletionItem> =
|
||||||
.into_iter()
|
completion_items.into_iter().filter(|c| c.completion_kind == kind).collect();
|
||||||
.filter(|c| c.completion_kind == kind)
|
|
||||||
.collect();
|
|
||||||
kind_completions.sort_by_key(|c| c.label.clone());
|
kind_completions.sort_by_key(|c| c.label.clone());
|
||||||
assert_debug_snapshot_matches!(test_name, kind_completions);
|
assert_debug_snapshot_matches!(test_name, kind_completions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
||||||
let source_root = db.file_source_root(file_id);
|
let source_root = db.file_source_root(file_id);
|
||||||
let diag = match problem {
|
let diag = match problem {
|
||||||
Problem::UnresolvedModule { candidate } => {
|
Problem::UnresolvedModule { candidate } => {
|
||||||
let create_file = FileSystemEdit::CreateFile {
|
let create_file =
|
||||||
source_root,
|
FileSystemEdit::CreateFile { source_root, path: candidate.clone() };
|
||||||
path: candidate.clone(),
|
|
||||||
};
|
|
||||||
let fix = SourceChange {
|
let fix = SourceChange {
|
||||||
label: "create module".to_string(),
|
label: "create module".to_string(),
|
||||||
source_file_edits: Vec::new(),
|
source_file_edits: Vec::new(),
|
||||||
|
@ -44,10 +42,8 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
|
||||||
dst_source_root: source_root,
|
dst_source_root: source_root,
|
||||||
dst_path: move_to.clone(),
|
dst_path: move_to.clone(),
|
||||||
};
|
};
|
||||||
let create_file = FileSystemEdit::CreateFile {
|
let create_file =
|
||||||
source_root,
|
FileSystemEdit::CreateFile { source_root, path: move_to.join(candidate) };
|
||||||
path: move_to.join(candidate),
|
|
||||||
};
|
|
||||||
let fix = SourceChange {
|
let fix = SourceChange {
|
||||||
label: "move file and create module".to_string(),
|
label: "move file and create module".to_string(),
|
||||||
source_file_edits: Vec::new(),
|
source_file_edits: Vec::new(),
|
||||||
|
|
|
@ -31,9 +31,7 @@ fn extend_selection_in_macro(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCall> {
|
fn find_macro_call(node: &SyntaxNode, range: TextRange) -> Option<&ast::MacroCall> {
|
||||||
find_covering_node(node, range)
|
find_covering_node(node, range).ancestors().find_map(ast::MacroCall::cast)
|
||||||
.ancestors()
|
|
||||||
.find_map(ast::MacroCall::cast)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -50,18 +50,13 @@ pub(crate) fn reference_definition(
|
||||||
hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())
|
hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())
|
||||||
{
|
{
|
||||||
// Check if it is a method
|
// Check if it is a method
|
||||||
if let Some(method_call) = name_ref
|
if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) {
|
||||||
.syntax()
|
|
||||||
.parent()
|
|
||||||
.and_then(ast::MethodCallExpr::cast)
|
|
||||||
{
|
|
||||||
tested_by!(goto_definition_works_for_methods);
|
tested_by!(goto_definition_works_for_methods);
|
||||||
let infer_result = function.infer(db);
|
let infer_result = function.infer(db);
|
||||||
let syntax_mapping = function.body_syntax_mapping(db);
|
let syntax_mapping = function.body_syntax_mapping(db);
|
||||||
let expr = ast::Expr::cast(method_call.syntax()).unwrap();
|
let expr = ast::Expr::cast(method_call.syntax()).unwrap();
|
||||||
if let Some(func) = syntax_mapping
|
if let Some(func) =
|
||||||
.node_expr(expr)
|
syntax_mapping.node_expr(expr).and_then(|it| infer_result.method_resolution(it))
|
||||||
.and_then(|it| infer_result.method_resolution(it))
|
|
||||||
{
|
{
|
||||||
return Exact(NavigationTarget::from_function(db, func));
|
return Exact(NavigationTarget::from_function(db, func));
|
||||||
};
|
};
|
||||||
|
@ -72,9 +67,8 @@ pub(crate) fn reference_definition(
|
||||||
let infer_result = function.infer(db);
|
let infer_result = function.infer(db);
|
||||||
let syntax_mapping = function.body_syntax_mapping(db);
|
let syntax_mapping = function.body_syntax_mapping(db);
|
||||||
let expr = ast::Expr::cast(field_expr.syntax()).unwrap();
|
let expr = ast::Expr::cast(field_expr.syntax()).unwrap();
|
||||||
if let Some(field) = syntax_mapping
|
if let Some(field) =
|
||||||
.node_expr(expr)
|
syntax_mapping.node_expr(expr).and_then(|it| infer_result.field_resolution(it))
|
||||||
.and_then(|it| infer_result.field_resolution(it))
|
|
||||||
{
|
{
|
||||||
return Exact(NavigationTarget::from_field(db, field));
|
return Exact(NavigationTarget::from_field(db, field));
|
||||||
};
|
};
|
||||||
|
@ -82,29 +76,19 @@ pub(crate) fn reference_definition(
|
||||||
}
|
}
|
||||||
// Try name resolution
|
// Try name resolution
|
||||||
let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax());
|
let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax());
|
||||||
if let Some(path) = name_ref
|
if let Some(path) =
|
||||||
.syntax()
|
name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast)
|
||||||
.ancestors()
|
|
||||||
.find_map(ast::Path::cast)
|
|
||||||
.and_then(hir::Path::from_ast)
|
|
||||||
{
|
{
|
||||||
let resolved = resolver.resolve_path(db, &path);
|
let resolved = resolver.resolve_path(db, &path);
|
||||||
match resolved
|
match resolved.clone().take_types().or_else(|| resolved.take_values()) {
|
||||||
.clone()
|
|
||||||
.take_types()
|
|
||||||
.or_else(|| resolved.take_values())
|
|
||||||
{
|
|
||||||
Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
|
Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
|
||||||
Some(Resolution::LocalBinding(pat)) => {
|
Some(Resolution::LocalBinding(pat)) => {
|
||||||
let body = resolver.body().expect("no body for local binding");
|
let body = resolver.body().expect("no body for local binding");
|
||||||
let syntax_mapping = body.syntax_mapping(db);
|
let syntax_mapping = body.syntax_mapping(db);
|
||||||
let ptr = syntax_mapping
|
let ptr =
|
||||||
.pat_syntax(pat)
|
syntax_mapping.pat_syntax(pat).expect("pattern not found in syntax mapping");
|
||||||
.expect("pattern not found in syntax mapping");
|
let name =
|
||||||
let name = path
|
path.as_ident().cloned().expect("local binding from a multi-segment path");
|
||||||
.as_ident()
|
|
||||||
.cloned()
|
|
||||||
.expect("local binding from a multi-segment path");
|
|
||||||
let nav = NavigationTarget::from_scope_entry(file_id, name, ptr);
|
let nav = NavigationTarget::from_scope_entry(file_id, name, ptr);
|
||||||
return Exact(nav);
|
return Exact(nav);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||||
}
|
}
|
||||||
if range.is_none() {
|
if range.is_none() {
|
||||||
let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| {
|
let node = find_leaf_at_offset(file.syntax(), position.offset).find_map(|leaf| {
|
||||||
leaf.ancestors()
|
leaf.ancestors().find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
|
||||||
.find(|n| ast::Expr::cast(*n).is_some() || ast::Pat::cast(*n).is_some())
|
|
||||||
})?;
|
})?;
|
||||||
let frange = FileRange {
|
let frange = FileRange { file_id: position.file_id, range: node.range() };
|
||||||
file_id: position.file_id,
|
|
||||||
range: node.range(),
|
|
||||||
};
|
|
||||||
res.extend(type_of(db, frange).map(Into::into));
|
res.extend(type_of(db, frange).map(Into::into));
|
||||||
range = Some(node.range());
|
range = Some(node.range());
|
||||||
};
|
};
|
||||||
|
@ -126,10 +122,8 @@ impl NavigationTarget {
|
||||||
where
|
where
|
||||||
T: ast::NameOwner + ast::VisibilityOwner,
|
T: ast::NameOwner + ast::VisibilityOwner,
|
||||||
{
|
{
|
||||||
let mut string = node
|
let mut string =
|
||||||
.visibility()
|
node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default();
|
||||||
.map(|v| format!("{} ", v.syntax().text()))
|
|
||||||
.unwrap_or_default();
|
|
||||||
string.push_str(label);
|
string.push_str(label);
|
||||||
node.name()?.syntax().text().push_to(&mut string);
|
node.name()?.syntax().text().push_to(&mut string);
|
||||||
Some(string)
|
Some(string)
|
||||||
|
|
|
@ -83,9 +83,7 @@ mod tests {
|
||||||
|
|
||||||
let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
|
let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
|
||||||
assert_eq!(navs.len(), expected.len());
|
assert_eq!(navs.len(), expected.len());
|
||||||
navs.into_iter()
|
navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
|
||||||
.enumerate()
|
|
||||||
.for_each(|(i, nav)| nav.assert_match(expected[i]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -109,10 +107,7 @@ mod tests {
|
||||||
impl Foo {}
|
impl Foo {}
|
||||||
impl Foo {}
|
impl Foo {}
|
||||||
",
|
",
|
||||||
&[
|
&["impl IMPL_BLOCK FileId(1) [12; 23)", "impl IMPL_BLOCK FileId(1) [24; 35)"],
|
||||||
"impl IMPL_BLOCK FileId(1) [12; 23)",
|
|
||||||
"impl IMPL_BLOCK FileId(1) [24; 35)",
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,10 +124,7 @@ mod tests {
|
||||||
impl super::Foo {}
|
impl super::Foo {}
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
&[
|
&["impl IMPL_BLOCK FileId(1) [24; 42)", "impl IMPL_BLOCK FileId(1) [57; 75)"],
|
||||||
"impl IMPL_BLOCK FileId(1) [24; 42)",
|
|
||||||
"impl IMPL_BLOCK FileId(1) [57; 75)",
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,10 +141,7 @@ mod tests {
|
||||||
//- /b.rs
|
//- /b.rs
|
||||||
impl crate::Foo {}
|
impl crate::Foo {}
|
||||||
",
|
",
|
||||||
&[
|
&["impl IMPL_BLOCK FileId(2) [0; 18)", "impl IMPL_BLOCK FileId(3) [0; 18)"],
|
||||||
"impl IMPL_BLOCK FileId(2) [0; 18)",
|
|
||||||
"impl IMPL_BLOCK FileId(3) [0; 18)",
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,10 +172,7 @@ mod tests {
|
||||||
//- /b.rs
|
//- /b.rs
|
||||||
impl crate::T for crate::Foo {}
|
impl crate::T for crate::Foo {}
|
||||||
",
|
",
|
||||||
&[
|
&["impl IMPL_BLOCK FileId(2) [0; 31)", "impl IMPL_BLOCK FileId(3) [0; 31)"],
|
||||||
"impl IMPL_BLOCK FileId(2) [0; 31)",
|
|
||||||
"impl IMPL_BLOCK FileId(3) [0; 31)",
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,15 +90,8 @@ pub struct SourceFileEdit {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FileSystemEdit {
|
pub enum FileSystemEdit {
|
||||||
CreateFile {
|
CreateFile { source_root: SourceRootId, path: RelativePathBuf },
|
||||||
source_root: SourceRootId,
|
MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf },
|
||||||
path: RelativePathBuf,
|
|
||||||
},
|
|
||||||
MoveFile {
|
|
||||||
src: FileId,
|
|
||||||
dst_source_root: SourceRootId,
|
|
||||||
dst_path: RelativePathBuf,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -179,9 +172,7 @@ impl AnalysisHost {
|
||||||
/// Returns a snapshot of the current state, which you can query for
|
/// Returns a snapshot of the current state, which you can query for
|
||||||
/// semantic information.
|
/// semantic information.
|
||||||
pub fn analysis(&self) -> Analysis {
|
pub fn analysis(&self) -> Analysis {
|
||||||
Analysis {
|
Analysis { db: self.db.snapshot() }
|
||||||
db: self.db.snapshot(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies changes to the current state of the world. If there are
|
/// Applies changes to the current state of the world. If there are
|
||||||
|
@ -401,17 +392,12 @@ impl Analysis {
|
||||||
|
|
||||||
impl SourceChange {
|
impl SourceChange {
|
||||||
pub(crate) fn from_local_edit(file_id: FileId, edit: LocalEdit) -> SourceChange {
|
pub(crate) fn from_local_edit(file_id: FileId, edit: LocalEdit) -> SourceChange {
|
||||||
let file_edit = SourceFileEdit {
|
let file_edit = SourceFileEdit { file_id, edit: edit.edit };
|
||||||
file_id,
|
|
||||||
edit: edit.edit,
|
|
||||||
};
|
|
||||||
SourceChange {
|
SourceChange {
|
||||||
label: edit.label,
|
label: edit.label,
|
||||||
source_file_edits: vec![file_edit],
|
source_file_edits: vec![file_edit],
|
||||||
file_system_edits: vec![],
|
file_system_edits: vec![],
|
||||||
cursor_position: edit
|
cursor_position: edit.cursor_position.map(|offset| FilePosition { offset, file_id }),
|
||||||
.cursor_position
|
|
||||||
.map(|offset| FilePosition { offset, file_id }),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,7 @@ impl MockAnalysis {
|
||||||
let mut res = MockAnalysis::new();
|
let mut res = MockAnalysis::new();
|
||||||
for entry in parse_fixture(fixture) {
|
for entry in parse_fixture(fixture) {
|
||||||
if entry.text.contains(CURSOR_MARKER) {
|
if entry.text.contains(CURSOR_MARKER) {
|
||||||
assert!(
|
assert!(position.is_none(), "only one marker (<|>) per fixture is allowed");
|
||||||
position.is_none(),
|
|
||||||
"only one marker (<|>) per fixture is allowed"
|
|
||||||
);
|
|
||||||
position = Some(res.add_file_with_position(&entry.meta, &entry.text));
|
position = Some(res.add_file_with_position(&entry.meta, &entry.text));
|
||||||
} else {
|
} else {
|
||||||
res.add_file(&entry.meta, &entry.text);
|
res.add_file(&entry.meta, &entry.text);
|
||||||
|
@ -97,9 +94,7 @@ impl MockAnalysis {
|
||||||
let other_crate = crate_graph.add_crate_root(file_id);
|
let other_crate = crate_graph.add_crate_root(file_id);
|
||||||
let crate_name = path.parent().unwrap().file_name().unwrap();
|
let crate_name = path.parent().unwrap().file_name().unwrap();
|
||||||
if let Some(root_crate) = root_crate {
|
if let Some(root_crate) = root_crate {
|
||||||
crate_graph
|
crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap();
|
||||||
.add_dep(root_crate, crate_name.into(), other_crate)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
change.add_file(source_root, file_id, path, Arc::new(contents));
|
change.add_file(source_root, file_id, path, Arc::new(contents));
|
||||||
|
|
|
@ -72,10 +72,7 @@ impl NavigationTarget {
|
||||||
|
|
||||||
pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
||||||
let (file_id, source) = module.definition_source(db);
|
let (file_id, source) = module.definition_source(db);
|
||||||
let name = module
|
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
|
||||||
.name(db)
|
|
||||||
.map(|it| it.to_string().into())
|
|
||||||
.unwrap_or_default();
|
|
||||||
match source {
|
match source {
|
||||||
ModuleSource::SourceFile(node) => {
|
ModuleSource::SourceFile(node) => {
|
||||||
NavigationTarget::from_syntax(file_id, name, None, node.syntax())
|
NavigationTarget::from_syntax(file_id, name, None, node.syntax())
|
||||||
|
@ -87,10 +84,7 @@ impl NavigationTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
||||||
let name = module
|
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
|
||||||
.name(db)
|
|
||||||
.map(|it| it.to_string().into())
|
|
||||||
.unwrap_or_default();
|
|
||||||
if let Some((file_id, source)) = module.declaration_source(db) {
|
if let Some((file_id, source)) = module.declaration_source(db) {
|
||||||
return NavigationTarget::from_syntax(file_id, name, None, source.syntax());
|
return NavigationTarget::from_syntax(file_id, name, None, source.syntax());
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,9 +305,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = text_edit_bulder
|
let result = text_edit_bulder.finish().apply(&*analysis.file_text(file_id.unwrap()));
|
||||||
.finish()
|
|
||||||
.apply(&*analysis.file_text(file_id.unwrap()));
|
|
||||||
assert_eq_text!(expected, &*result);
|
assert_eq_text!(expected, &*result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,7 @@ pub enum RunnableKind {
|
||||||
|
|
||||||
pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
|
pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
|
||||||
let source_file = db.parse(file_id);
|
let source_file = db.parse(file_id);
|
||||||
source_file
|
source_file.syntax().descendants().filter_map(|i| runnable(db, file_id, i)).collect()
|
||||||
.syntax()
|
|
||||||
.descendants()
|
|
||||||
.filter_map(|i| runnable(db, file_id, i))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> {
|
fn runnable(db: &RootDatabase, file_id: FileId, item: &SyntaxNode) -> Option<Runnable> {
|
||||||
|
@ -45,20 +41,13 @@ fn runnable_fn(fn_def: &ast::FnDef) -> Option<Runnable> {
|
||||||
let kind = if name == "main" {
|
let kind = if name == "main" {
|
||||||
RunnableKind::Bin
|
RunnableKind::Bin
|
||||||
} else if fn_def.has_atom_attr("test") {
|
} else if fn_def.has_atom_attr("test") {
|
||||||
RunnableKind::Test {
|
RunnableKind::Test { name: name.to_string() }
|
||||||
name: name.to_string(),
|
|
||||||
}
|
|
||||||
} else if fn_def.has_atom_attr("bench") {
|
} else if fn_def.has_atom_attr("bench") {
|
||||||
RunnableKind::Bench {
|
RunnableKind::Bench { name: name.to_string() }
|
||||||
name: name.to_string(),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some(Runnable {
|
Some(Runnable { range: fn_def.syntax().range(), kind })
|
||||||
range: fn_def.syntax().range(),
|
|
||||||
kind,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runnable_mod(db: &RootDatabase, file_id: FileId, module: &ast::Module) -> Option<Runnable> {
|
fn runnable_mod(db: &RootDatabase, file_id: FileId, module: &ast::Module) -> Option<Runnable> {
|
||||||
|
@ -77,16 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: &ast::Module) -> Opt
|
||||||
let module = hir::source_binder::module_from_child_node(db, file_id, module.syntax())?;
|
let module = hir::source_binder::module_from_child_node(db, file_id, module.syntax())?;
|
||||||
|
|
||||||
// FIXME: thread cancellation instead of `.ok`ing
|
// FIXME: thread cancellation instead of `.ok`ing
|
||||||
let path = module
|
let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
|
||||||
.path_to_root(db)
|
Some(Runnable { range, kind: RunnableKind::TestMod { path } })
|
||||||
.into_iter()
|
|
||||||
.rev()
|
|
||||||
.filter_map(|it| it.name(db))
|
|
||||||
.join("::");
|
|
||||||
Some(Runnable {
|
|
||||||
range,
|
|
||||||
kind: RunnableKind::TestMod { path },
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -22,9 +22,7 @@ pub(crate) fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
|
||||||
pub(crate) fn status(db: &RootDatabase) -> String {
|
pub(crate) fn status(db: &RootDatabase) -> String {
|
||||||
let files_stats = db.query(FileTextQuery).entries::<FilesStats>();
|
let files_stats = db.query(FileTextQuery).entries::<FilesStats>();
|
||||||
let syntax_tree_stats = syntax_tree_stats(db);
|
let syntax_tree_stats = syntax_tree_stats(db);
|
||||||
let symbols_stats = db
|
let symbols_stats = db.query(LibrarySymbolsQuery).entries::<LibrarySymbolsStats>();
|
||||||
.query(LibrarySymbolsQuery)
|
|
||||||
.entries::<LibrarySymbolsStats>();
|
|
||||||
let n_defs = {
|
let n_defs = {
|
||||||
let interner: &hir::HirInterner = db.as_ref();
|
let interner: &hir::HirInterner = db.as_ref();
|
||||||
interner.len()
|
interner.len()
|
||||||
|
@ -75,11 +73,7 @@ pub(crate) struct SyntaxTreeStats {
|
||||||
|
|
||||||
impl fmt::Display for SyntaxTreeStats {
|
impl fmt::Display for SyntaxTreeStats {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(fmt, "{} trees, {} ({}) retained", self.total, self.retained, self.retained_size,)
|
||||||
fmt,
|
|
||||||
"{} trees, {} ({}) retained",
|
|
||||||
self.total, self.retained, self.retained_size,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,20 +138,13 @@ impl MemoryStats {
|
||||||
|
|
||||||
#[cfg(not(feature = "jemalloc"))]
|
#[cfg(not(feature = "jemalloc"))]
|
||||||
fn current() -> MemoryStats {
|
fn current() -> MemoryStats {
|
||||||
MemoryStats {
|
MemoryStats { allocated: Bytes(0), resident: Bytes(0) }
|
||||||
allocated: Bytes(0),
|
|
||||||
resident: Bytes(0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for MemoryStats {
|
impl fmt::Display for MemoryStats {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(fmt, "{} allocated {} resident", self.allocated, self.resident,)
|
||||||
fmt,
|
|
||||||
"{} allocated {} resident",
|
|
||||||
self.allocated, self.resident,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,10 +101,7 @@ pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol>
|
||||||
}
|
}
|
||||||
|
|
||||||
let snap = Snap(db.snapshot());
|
let snap = Snap(db.snapshot());
|
||||||
files
|
files.par_iter().map_with(snap, |db, &file_id| db.0.file_symbols(file_id)).collect()
|
||||||
.par_iter()
|
|
||||||
.map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
|
|
||||||
.collect()
|
|
||||||
};
|
};
|
||||||
query.search(&buf)
|
query.search(&buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,12 @@ use crate::{
|
||||||
pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
|
pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
|
||||||
let source_file = db.parse(file_id);
|
let source_file = db.parse(file_id);
|
||||||
let mut res = ra_ide_api_light::highlight(source_file.syntax());
|
let mut res = ra_ide_api_light::highlight(source_file.syntax());
|
||||||
for macro_call in source_file
|
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {
|
||||||
.syntax()
|
|
||||||
.descendants()
|
|
||||||
.filter_map(ast::MacroCall::cast)
|
|
||||||
{
|
|
||||||
if let Some((off, exp)) = hir::MacroDef::ast_expand(macro_call) {
|
if let Some((off, exp)) = hir::MacroDef::ast_expand(macro_call) {
|
||||||
let mapped_ranges = ra_ide_api_light::highlight(&exp.syntax())
|
let mapped_ranges =
|
||||||
.into_iter()
|
ra_ide_api_light::highlight(&exp.syntax()).into_iter().filter_map(|r| {
|
||||||
.filter_map(|r| {
|
|
||||||
let mapped_range = exp.map_range_back(r.range)?;
|
let mapped_range = exp.map_range_back(r.range)?;
|
||||||
let res = HighlightedRange {
|
let res = HighlightedRange { range: mapped_range + off, tag: r.tag };
|
||||||
range: mapped_range + off,
|
|
||||||
tag: r.tag,
|
|
||||||
};
|
|
||||||
Some(res)
|
Some(res)
|
||||||
});
|
});
|
||||||
res.extend(mapped_ranges);
|
res.extend(mapped_ranges);
|
||||||
|
|
|
@ -72,14 +72,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
|
||||||
single_use_tree: &ast::UseTree,
|
single_use_tree: &ast::UseTree,
|
||||||
) -> Option<TextEdit> {
|
) -> Option<TextEdit> {
|
||||||
let use_tree_list_node = single_use_tree.syntax().parent()?;
|
let use_tree_list_node = single_use_tree.syntax().parent()?;
|
||||||
if single_use_tree
|
if single_use_tree.path()?.segment()?.syntax().first_child()?.kind() == SyntaxKind::SELF_KW {
|
||||||
.path()?
|
|
||||||
.segment()?
|
|
||||||
.syntax()
|
|
||||||
.first_child()?
|
|
||||||
.kind()
|
|
||||||
== SyntaxKind::SELF_KW
|
|
||||||
{
|
|
||||||
let start = use_tree_list_node.prev_sibling()?.range().start();
|
let start = use_tree_list_node.prev_sibling()?.range().start();
|
||||||
let end = use_tree_list_node.range().end();
|
let end = use_tree_list_node.range().end();
|
||||||
let range = TextRange::from_to(start, end);
|
let range = TextRange::from_to(start, end);
|
||||||
|
@ -145,9 +138,8 @@ mod tests {
|
||||||
for node in file.syntax().descendants() {
|
for node in file.syntax().descendants() {
|
||||||
func(&mut diagnostics, node);
|
func(&mut diagnostics, node);
|
||||||
}
|
}
|
||||||
let diagnostic = diagnostics
|
let diagnostic =
|
||||||
.pop()
|
diagnostics.pop().unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
|
||||||
.unwrap_or_else(|| panic!("no diagnostics for:\n{}\n", before));
|
|
||||||
let fix = diagnostic.fix.unwrap();
|
let fix = diagnostic.fix.unwrap();
|
||||||
let actual = fix.edit.apply(&before);
|
let actual = fix.edit.apply(&before);
|
||||||
assert_eq_text!(after, &actual);
|
assert_eq_text!(after, &actual);
|
||||||
|
@ -162,21 +154,9 @@ mod tests {
|
||||||
",
|
",
|
||||||
check_unnecessary_braces_in_use_statement,
|
check_unnecessary_braces_in_use_statement,
|
||||||
);
|
);
|
||||||
check_apply(
|
check_apply("use {b};", "use b;", check_unnecessary_braces_in_use_statement);
|
||||||
"use {b};",
|
check_apply("use a::{c};", "use a::c;", check_unnecessary_braces_in_use_statement);
|
||||||
"use b;",
|
check_apply("use a::{self};", "use a;", check_unnecessary_braces_in_use_statement);
|
||||||
check_unnecessary_braces_in_use_statement,
|
|
||||||
);
|
|
||||||
check_apply(
|
|
||||||
"use a::{c};",
|
|
||||||
"use a::c;",
|
|
||||||
check_unnecessary_braces_in_use_statement,
|
|
||||||
);
|
|
||||||
check_apply(
|
|
||||||
"use a::{self};",
|
|
||||||
"use a;",
|
|
||||||
check_unnecessary_braces_in_use_statement,
|
|
||||||
);
|
|
||||||
check_apply(
|
check_apply(
|
||||||
"use a::{c, d::{e}};",
|
"use a::{c, d::{e}};",
|
||||||
"use a::{c, d::e};",
|
"use a::{c, d::e};",
|
||||||
|
|
|
@ -43,11 +43,7 @@ pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
|
||||||
let node = find_covering_node(root, range);
|
let node = find_covering_node(root, range);
|
||||||
|
|
||||||
// Using shallowest node with same range allows us to traverse siblings.
|
// Using shallowest node with same range allows us to traverse siblings.
|
||||||
let node = node
|
let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap();
|
||||||
.ancestors()
|
|
||||||
.take_while(|n| n.range() == node.range())
|
|
||||||
.last()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if range == node.range() {
|
if range == node.range() {
|
||||||
if string_kinds.contains(&node.kind()) {
|
if string_kinds.contains(&node.kind()) {
|
||||||
|
@ -145,10 +141,7 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
|
if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
|
||||||
return Some(TextRange::from_to(
|
return Some(TextRange::from_to(comma_node.range().start(), node.range().end()));
|
||||||
comma_node.range().start(),
|
|
||||||
node.range().end(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(comma_node) = nearby_comma(node, Direction::Next) {
|
if let Some(comma_node) = nearby_comma(node, Direction::Next) {
|
||||||
|
@ -160,10 +153,7 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
|
||||||
.filter(|node| is_single_line_ws(node))
|
.filter(|node| is_single_line_ws(node))
|
||||||
.unwrap_or(comma_node);
|
.unwrap_or(comma_node);
|
||||||
|
|
||||||
return Some(TextRange::from_to(
|
return Some(TextRange::from_to(node.range().start(), final_node.range().end()));
|
||||||
node.range().start(),
|
|
||||||
final_node.range().end(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
return None;
|
||||||
|
@ -217,36 +207,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extend_selection_list() {
|
fn test_extend_selection_list() {
|
||||||
do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
|
do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
|
||||||
do_check(
|
do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]);
|
||||||
r#"fn foo(<|>x: i32, y: i32) {}"#,
|
do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,"]);
|
||||||
&["x", "x: i32", "x: i32, "],
|
do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]);
|
||||||
);
|
do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", ", y: i32"]);
|
||||||
do_check(
|
do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]);
|
||||||
r#"fn foo(<|>x: i32,y: i32) {}"#,
|
|
||||||
&["x", "x: i32", "x: i32,"],
|
|
||||||
);
|
|
||||||
do_check(
|
|
||||||
r#"fn foo(x: i32, <|>y: i32) {}"#,
|
|
||||||
&["y", "y: i32", ", y: i32"],
|
|
||||||
);
|
|
||||||
do_check(
|
|
||||||
r#"fn foo(x: i32, <|>y: i32, ) {}"#,
|
|
||||||
&["y", "y: i32", ", y: i32"],
|
|
||||||
);
|
|
||||||
do_check(
|
|
||||||
r#"fn foo(x: i32,<|>y: i32) {}"#,
|
|
||||||
&["y", "y: i32", ",y: i32"],
|
|
||||||
);
|
|
||||||
|
|
||||||
do_check(
|
do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]);
|
||||||
r#"const FOO: [usize; 2] = [ 22<|> , 33];"#,
|
|
||||||
&["22", "22 , "],
|
|
||||||
);
|
|
||||||
do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
|
do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
|
||||||
do_check(
|
do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", ", 33"]);
|
||||||
r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#,
|
|
||||||
&["33", ", 33"],
|
|
||||||
);
|
|
||||||
|
|
||||||
do_check(
|
do_check(
|
||||||
r#"
|
r#"
|
||||||
|
@ -292,11 +261,7 @@ struct B {
|
||||||
<|>
|
<|>
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
&[
|
&["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"],
|
||||||
"\n \n",
|
|
||||||
"{\n \n}",
|
|
||||||
"/// bla\n/// bla\nstruct B {\n \n}",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,30 +30,21 @@ pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
|
||||||
// Fold items that span multiple lines
|
// Fold items that span multiple lines
|
||||||
if let Some(kind) = fold_kind(node.kind()) {
|
if let Some(kind) = fold_kind(node.kind()) {
|
||||||
if node.text().contains('\n') {
|
if node.text().contains('\n') {
|
||||||
res.push(Fold {
|
res.push(Fold { range: node.range(), kind });
|
||||||
range: node.range(),
|
|
||||||
kind,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fold groups of comments
|
// Fold groups of comments
|
||||||
if node.kind() == COMMENT && !visited_comments.contains(&node) {
|
if node.kind() == COMMENT && !visited_comments.contains(&node) {
|
||||||
if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) {
|
if let Some(range) = contiguous_range_for_comment(node, &mut visited_comments) {
|
||||||
res.push(Fold {
|
res.push(Fold { range, kind: FoldKind::Comment })
|
||||||
range,
|
|
||||||
kind: FoldKind::Comment,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fold groups of imports
|
// Fold groups of imports
|
||||||
if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
|
if node.kind() == USE_ITEM && !visited_imports.contains(&node) {
|
||||||
if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) {
|
if let Some(range) = contiguous_range_for_group(node, &mut visited_imports) {
|
||||||
res.push(Fold {
|
res.push(Fold { range, kind: FoldKind::Imports })
|
||||||
range,
|
|
||||||
kind: FoldKind::Imports,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,10 +53,7 @@ pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
|
||||||
if let Some(range) =
|
if let Some(range) =
|
||||||
contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods)
|
contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods)
|
||||||
{
|
{
|
||||||
res.push(Fold {
|
res.push(Fold { range, kind: FoldKind::Mods })
|
||||||
range,
|
|
||||||
kind: FoldKind::Mods,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,9 +72,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_visibility(node: &SyntaxNode) -> bool {
|
fn has_visibility(node: &SyntaxNode) -> bool {
|
||||||
ast::Module::cast(node)
|
ast::Module::cast(node).and_then(|m| m.visibility()).is_some()
|
||||||
.and_then(|m| m.visibility())
|
|
||||||
.is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contiguous_range_for_group<'a>(
|
fn contiguous_range_for_group<'a>(
|
||||||
|
@ -125,10 +111,7 @@ fn contiguous_range_for_group_unless<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if first != last {
|
if first != last {
|
||||||
Some(TextRange::from_to(
|
Some(TextRange::from_to(first.range().start(), last.range().end()))
|
||||||
first.range().start(),
|
|
||||||
last.range().end(),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// The group consists of only one element, therefore it cannot be folded
|
// The group consists of only one element, therefore it cannot be folded
|
||||||
None
|
None
|
||||||
|
@ -169,10 +152,7 @@ fn contiguous_range_for_comment<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if first != last {
|
if first != last {
|
||||||
Some(TextRange::from_to(
|
Some(TextRange::from_to(first.range().start(), last.range().end()))
|
||||||
first.range().start(),
|
|
||||||
last.range().end(),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// The group consists of only one element, therefore it cannot be folded
|
// The group consists of only one element, therefore it cannot be folded
|
||||||
None
|
None
|
||||||
|
@ -199,10 +179,8 @@ mod tests {
|
||||||
fold_kinds.len(),
|
fold_kinds.len(),
|
||||||
"The amount of fold kinds is different than the expected amount"
|
"The amount of fold kinds is different than the expected amount"
|
||||||
);
|
);
|
||||||
for ((fold, range), fold_kind) in folds
|
for ((fold, range), fold_kind) in
|
||||||
.into_iter()
|
folds.into_iter().zip(ranges.into_iter()).zip(fold_kinds.into_iter())
|
||||||
.zip(ranges.into_iter())
|
|
||||||
.zip(fold_kinds.into_iter())
|
|
||||||
{
|
{
|
||||||
assert_eq!(fold.range.start(), range.start());
|
assert_eq!(fold.range.start(), range.start());
|
||||||
assert_eq!(fold.range.end(), range.end());
|
assert_eq!(fold.range.end(), range.end());
|
||||||
|
@ -280,12 +258,7 @@ mod with_attribute_next;</fold>
|
||||||
fn main() <fold>{
|
fn main() <fold>{
|
||||||
}</fold>"#;
|
}</fold>"#;
|
||||||
|
|
||||||
let folds = &[
|
let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
|
||||||
FoldKind::Mods,
|
|
||||||
FoldKind::Mods,
|
|
||||||
FoldKind::Mods,
|
|
||||||
FoldKind::Block,
|
|
||||||
];
|
|
||||||
do_check(text, folds);
|
do_check(text, folds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,7 @@ fn prev_leaves(node: &SyntaxNode) -> impl Iterator<Item = &SyntaxNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> {
|
fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> {
|
||||||
generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| {
|
generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| it.last_child()).last()
|
||||||
it.last_child()
|
|
||||||
})
|
|
||||||
.last()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
|
pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
|
||||||
|
|
|
@ -50,11 +50,7 @@ pub fn join_lines(file: &SourceFile, range: TextRange) -> LocalEdit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalEdit {
|
LocalEdit { label: "join lines".to_string(), edit: edit.finish(), cursor_position: None }
|
||||||
label: "join lines".to_string(),
|
|
||||||
edit: edit.finish(),
|
|
||||||
cursor_position: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_newline(
|
fn remove_newline(
|
||||||
|
@ -71,10 +67,7 @@ fn remove_newline(
|
||||||
)];
|
)];
|
||||||
let spaces = suff.bytes().take_while(|&b| b == b' ').count();
|
let spaces = suff.bytes().take_while(|&b| b == b' ').count();
|
||||||
|
|
||||||
edit.replace(
|
edit.replace(TextRange::offset_len(offset, ((spaces + 1) as u32).into()), " ".to_string());
|
||||||
TextRange::offset_len(offset, ((spaces + 1) as u32).into()),
|
|
||||||
" ".to_string(),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +102,7 @@ fn remove_newline(
|
||||||
edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
|
edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
|
||||||
} else if prev.kind() == COMMA && next.kind() == R_CURLY {
|
} else if prev.kind() == COMMA && next.kind() == R_CURLY {
|
||||||
// Removes: comma, newline (incl. surrounding whitespace)
|
// Removes: comma, newline (incl. surrounding whitespace)
|
||||||
let space = if let Some(left) = prev.prev_sibling() {
|
let space = if let Some(left) = prev.prev_sibling() { compute_ws(left, next) } else { " " };
|
||||||
compute_ws(left, next)
|
|
||||||
} else {
|
|
||||||
" "
|
|
||||||
};
|
|
||||||
edit.replace(
|
edit.replace(
|
||||||
TextRange::from_to(prev.range().start(), node.range().end()),
|
TextRange::from_to(prev.range().start(), node.range().end()),
|
||||||
space.to_string(),
|
space.to_string(),
|
||||||
|
@ -134,20 +123,14 @@ fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Opti
|
||||||
let block = ast::Block::cast(node.parent()?)?;
|
let block = ast::Block::cast(node.parent()?)?;
|
||||||
let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
|
let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
|
||||||
let expr = extract_trivial_expression(block)?;
|
let expr = extract_trivial_expression(block)?;
|
||||||
edit.replace(
|
edit.replace(block_expr.syntax().range(), expr.syntax().text().to_string());
|
||||||
block_expr.syntax().range(),
|
|
||||||
expr.syntax().text().to_string(),
|
|
||||||
);
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
|
fn join_single_use_tree(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
|
||||||
let use_tree_list = ast::UseTreeList::cast(node.parent()?)?;
|
let use_tree_list = ast::UseTreeList::cast(node.parent()?)?;
|
||||||
let (tree,) = use_tree_list.use_trees().collect_tuple()?;
|
let (tree,) = use_tree_list.use_trees().collect_tuple()?;
|
||||||
edit.replace(
|
edit.replace(use_tree_list.syntax().range(), tree.syntax().text().to_string());
|
||||||
use_tree_list.syntax().range(),
|
|
||||||
tree.syntax().text().to_string(),
|
|
||||||
);
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,8 @@ pub struct Diagnostic {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> {
|
pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> {
|
||||||
const BRACES: &[SyntaxKind] = &[
|
const BRACES: &[SyntaxKind] =
|
||||||
L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
|
&[L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE];
|
||||||
];
|
|
||||||
let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset)
|
let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset)
|
||||||
.filter_map(|node| {
|
.filter_map(|node| {
|
||||||
let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
|
let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
|
||||||
|
@ -74,9 +73,7 @@ pub fn matching_brace(file: &SourceFile, offset: TextUnit) -> Option<TextUnit> {
|
||||||
.next()?;
|
.next()?;
|
||||||
let parent = brace_node.parent()?;
|
let parent = brace_node.parent()?;
|
||||||
let matching_kind = BRACES[brace_idx ^ 1];
|
let matching_kind = BRACES[brace_idx ^ 1];
|
||||||
let matching_node = parent
|
let matching_node = parent.children().find(|node| node.kind() == matching_kind)?;
|
||||||
.children()
|
|
||||||
.find(|node| node.kind() == matching_kind)?;
|
|
||||||
Some(matching_node.range().start())
|
Some(matching_node.range().start())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,10 +119,7 @@ pub fn highlight(root: &SyntaxNode) -> Vec<HighlightedRange> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
res.push(HighlightedRange {
|
res.push(HighlightedRange { range: node.range(), tag })
|
||||||
range: node.range(),
|
|
||||||
tag,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,10 +54,7 @@ impl LineIndex {
|
||||||
|
|
||||||
let char_len = TextUnit::of_char(c);
|
let char_len = TextUnit::of_char(c);
|
||||||
if char_len.to_usize() > 1 {
|
if char_len.to_usize() > 1 {
|
||||||
utf16_chars.push(Utf16Char {
|
utf16_chars.push(Utf16Char { start: curr_col, end: curr_col + char_len });
|
||||||
start: curr_col,
|
|
||||||
end: curr_col + char_len,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curr_col += char_len;
|
curr_col += char_len;
|
||||||
|
@ -68,10 +65,7 @@ impl LineIndex {
|
||||||
utf16_lines.insert(line, utf16_chars);
|
utf16_lines.insert(line, utf16_chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
LineIndex {
|
LineIndex { newlines, utf16_lines }
|
||||||
newlines,
|
|
||||||
utf16_lines,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_col(&self, offset: TextUnit) -> LineCol {
|
pub fn line_col(&self, offset: TextUnit) -> LineCol {
|
||||||
|
@ -79,10 +73,7 @@ impl LineIndex {
|
||||||
let line_start_offset = self.newlines[line];
|
let line_start_offset = self.newlines[line];
|
||||||
let col = offset - line_start_offset;
|
let col = offset - line_start_offset;
|
||||||
|
|
||||||
LineCol {
|
LineCol { line: line as u32, col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32 }
|
||||||
line: line as u32,
|
|
||||||
col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&self, line_col: LineCol) -> TextUnit {
|
pub fn offset(&self, line_col: LineCol) -> TextUnit {
|
||||||
|
@ -131,10 +122,7 @@ impl LineIndex {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
/// Simple reference implementation to use in proptests
|
/// Simple reference implementation to use in proptests
|
||||||
pub fn to_line_col(text: &str, offset: TextUnit) -> LineCol {
|
pub fn to_line_col(text: &str, offset: TextUnit) -> LineCol {
|
||||||
let mut res = LineCol {
|
let mut res = LineCol { line: 0, col_utf16: 0 };
|
||||||
line: 0,
|
|
||||||
col_utf16: 0,
|
|
||||||
};
|
|
||||||
for (i, c) in text.char_indices() {
|
for (i, c) in text.char_indices() {
|
||||||
if i + c.len_utf8() > offset.to_usize() {
|
if i + c.len_utf8() > offset.to_usize() {
|
||||||
// if it's an invalid offset, inside a multibyte char
|
// if it's an invalid offset, inside a multibyte char
|
||||||
|
@ -161,120 +149,31 @@ mod test_line_index {
|
||||||
fn test_line_index() {
|
fn test_line_index() {
|
||||||
let text = "hello\nworld";
|
let text = "hello\nworld";
|
||||||
let index = LineIndex::new(text);
|
let index = LineIndex::new(text);
|
||||||
assert_eq!(
|
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||||
index.line_col(0.into()),
|
assert_eq!(index.line_col(1.into()), LineCol { line: 0, col_utf16: 1 });
|
||||||
LineCol {
|
assert_eq!(index.line_col(5.into()), LineCol { line: 0, col_utf16: 5 });
|
||||||
line: 0,
|
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 0 });
|
||||||
col_utf16: 0
|
assert_eq!(index.line_col(7.into()), LineCol { line: 1, col_utf16: 1 });
|
||||||
}
|
assert_eq!(index.line_col(8.into()), LineCol { line: 1, col_utf16: 2 });
|
||||||
);
|
assert_eq!(index.line_col(10.into()), LineCol { line: 1, col_utf16: 4 });
|
||||||
assert_eq!(
|
assert_eq!(index.line_col(11.into()), LineCol { line: 1, col_utf16: 5 });
|
||||||
index.line_col(1.into()),
|
assert_eq!(index.line_col(12.into()), LineCol { line: 1, col_utf16: 6 });
|
||||||
LineCol {
|
|
||||||
line: 0,
|
|
||||||
col_utf16: 1
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(5.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 0,
|
|
||||||
col_utf16: 5
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(6.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(7.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 1
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(8.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 2
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(10.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 4
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(11.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 5
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(12.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 6
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let text = "\nhello\nworld";
|
let text = "\nhello\nworld";
|
||||||
let index = LineIndex::new(text);
|
let index = LineIndex::new(text);
|
||||||
assert_eq!(
|
assert_eq!(index.line_col(0.into()), LineCol { line: 0, col_utf16: 0 });
|
||||||
index.line_col(0.into()),
|
assert_eq!(index.line_col(1.into()), LineCol { line: 1, col_utf16: 0 });
|
||||||
LineCol {
|
assert_eq!(index.line_col(2.into()), LineCol { line: 1, col_utf16: 1 });
|
||||||
line: 0,
|
assert_eq!(index.line_col(6.into()), LineCol { line: 1, col_utf16: 5 });
|
||||||
col_utf16: 0
|
assert_eq!(index.line_col(7.into()), LineCol { line: 2, col_utf16: 0 });
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(1.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(2.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 1
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(6.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 1,
|
|
||||||
col_utf16: 5
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index.line_col(7.into()),
|
|
||||||
LineCol {
|
|
||||||
line: 2,
|
|
||||||
col_utf16: 0
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arb_text_with_offset() -> BoxedStrategy<(TextUnit, String)> {
|
fn arb_text_with_offset() -> BoxedStrategy<(TextUnit, String)> {
|
||||||
arb_text()
|
arb_text().prop_flat_map(|text| (arb_offset(&text), Just(text))).boxed()
|
||||||
.prop_flat_map(|text| (arb_offset(&text), Just(text)))
|
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_line_col(text: &str, offset: TextUnit) -> LineCol {
|
fn to_line_col(text: &str, offset: TextUnit) -> LineCol {
|
||||||
let mut res = LineCol {
|
let mut res = LineCol { line: 0, col_utf16: 0 };
|
||||||
line: 0,
|
|
||||||
col_utf16: 0,
|
|
||||||
};
|
|
||||||
for (i, c) in text.char_indices() {
|
for (i, c) in text.char_indices() {
|
||||||
if i + c.len_utf8() > offset.to_usize() {
|
if i + c.len_utf8() > offset.to_usize() {
|
||||||
// if it's an invalid offset, inside a multibyte char
|
// if it's an invalid offset, inside a multibyte char
|
||||||
|
@ -333,13 +232,7 @@ const C: char = 'メ';
|
||||||
|
|
||||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||||
assert_eq!(col_index.utf16_lines[&1].len(), 1);
|
assert_eq!(col_index.utf16_lines[&1].len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||||
col_index.utf16_lines[&1][0],
|
|
||||||
Utf16Char {
|
|
||||||
start: 17.into(),
|
|
||||||
end: 20.into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// UTF-8 to UTF-16, no changes
|
// UTF-8 to UTF-16, no changes
|
||||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||||
|
@ -364,20 +257,8 @@ const C: char = \"メ メ\";
|
||||||
|
|
||||||
assert_eq!(col_index.utf16_lines.len(), 1);
|
assert_eq!(col_index.utf16_lines.len(), 1);
|
||||||
assert_eq!(col_index.utf16_lines[&1].len(), 2);
|
assert_eq!(col_index.utf16_lines[&1].len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(col_index.utf16_lines[&1][0], Utf16Char { start: 17.into(), end: 20.into() });
|
||||||
col_index.utf16_lines[&1][0],
|
assert_eq!(col_index.utf16_lines[&1][1], Utf16Char { start: 21.into(), end: 24.into() });
|
||||||
Utf16Char {
|
|
||||||
start: 17.into(),
|
|
||||||
end: 20.into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
col_index.utf16_lines[&1][1],
|
|
||||||
Utf16Char {
|
|
||||||
start: 21.into(),
|
|
||||||
end: 24.into()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// UTF-8 to UTF-16
|
// UTF-8 to UTF-16
|
||||||
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
|
||||||
|
|
|
@ -17,11 +17,7 @@ struct LineIndexStepIter<'a> {
|
||||||
|
|
||||||
impl<'a> LineIndexStepIter<'a> {
|
impl<'a> LineIndexStepIter<'a> {
|
||||||
fn from(line_index: &LineIndex) -> LineIndexStepIter {
|
fn from(line_index: &LineIndex) -> LineIndexStepIter {
|
||||||
let mut x = LineIndexStepIter {
|
let mut x = LineIndexStepIter { line_index, next_newline_idx: 0, utf16_chars: None };
|
||||||
line_index,
|
|
||||||
next_newline_idx: 0,
|
|
||||||
utf16_chars: None,
|
|
||||||
};
|
|
||||||
// skip first newline since it's not real
|
// skip first newline since it's not real
|
||||||
x.next();
|
x.next();
|
||||||
x
|
x
|
||||||
|
@ -35,10 +31,7 @@ impl<'a> Iterator for LineIndexStepIter<'a> {
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.and_then(|(newline, x)| {
|
.and_then(|(newline, x)| {
|
||||||
let x = x.next()?;
|
let x = x.next()?;
|
||||||
Some(Step::Utf16Char(TextRange::from_to(
|
Some(Step::Utf16Char(TextRange::from_to(*newline + x.start, *newline + x.end)))
|
||||||
*newline + x.start,
|
|
||||||
*newline + x.end,
|
|
||||||
)))
|
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?;
|
let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?;
|
||||||
|
@ -113,11 +106,7 @@ struct Edits<'a> {
|
||||||
|
|
||||||
impl<'a> Edits<'a> {
|
impl<'a> Edits<'a> {
|
||||||
fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> {
|
fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> {
|
||||||
let mut x = Edits {
|
let mut x = Edits { edits: text_edit.as_atoms(), current: None, acc_diff: 0 };
|
||||||
edits: text_edit.as_atoms(),
|
|
||||||
current: None,
|
|
||||||
acc_diff: 0,
|
|
||||||
};
|
|
||||||
x.advance_edit();
|
x.advance_edit();
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
@ -127,11 +116,7 @@ impl<'a> Edits<'a> {
|
||||||
Some((next, rest)) => {
|
Some((next, rest)) => {
|
||||||
let delete = self.translate_range(next.delete);
|
let delete = self.translate_range(next.delete);
|
||||||
let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64;
|
let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64;
|
||||||
self.current = Some(TranslatedEdit {
|
self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff });
|
||||||
delete,
|
|
||||||
insert: &next.insert,
|
|
||||||
diff,
|
|
||||||
});
|
|
||||||
self.edits = rest;
|
self.edits = rest;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
@ -142,10 +127,7 @@ impl<'a> Edits<'a> {
|
||||||
|
|
||||||
fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> {
|
fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> {
|
||||||
let cur = self.current.as_ref()?;
|
let cur = self.current.as_ref()?;
|
||||||
let res = Some(OffsetStepIter {
|
let res = Some(OffsetStepIter { offset: cur.delete.start(), text: &cur.insert });
|
||||||
offset: cur.delete.start(),
|
|
||||||
text: &cur.insert,
|
|
||||||
});
|
|
||||||
self.advance_edit();
|
self.advance_edit();
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -160,18 +142,12 @@ impl<'a> Edits<'a> {
|
||||||
if step_pos <= edit.delete.start() {
|
if step_pos <= edit.delete.start() {
|
||||||
NextSteps::Use
|
NextSteps::Use
|
||||||
} else if step_pos <= edit.delete.end() {
|
} else if step_pos <= edit.delete.end() {
|
||||||
let iter = OffsetStepIter {
|
let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
|
||||||
offset: edit.delete.start(),
|
|
||||||
text: &edit.insert,
|
|
||||||
};
|
|
||||||
// empty slice to avoid returning steps again
|
// empty slice to avoid returning steps again
|
||||||
edit.insert = &edit.insert[edit.insert.len()..];
|
edit.insert = &edit.insert[edit.insert.len()..];
|
||||||
NextSteps::ReplaceMany(iter)
|
NextSteps::ReplaceMany(iter)
|
||||||
} else {
|
} else {
|
||||||
let iter = OffsetStepIter {
|
let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
|
||||||
offset: edit.delete.start(),
|
|
||||||
text: &edit.insert,
|
|
||||||
};
|
|
||||||
// empty slice to avoid returning steps again
|
// empty slice to avoid returning steps again
|
||||||
edit.insert = &edit.insert[edit.insert.len()..];
|
edit.insert = &edit.insert[edit.insert.len()..];
|
||||||
self.advance_edit();
|
self.advance_edit();
|
||||||
|
@ -222,11 +198,7 @@ struct RunningLineCol {
|
||||||
|
|
||||||
impl RunningLineCol {
|
impl RunningLineCol {
|
||||||
fn new() -> RunningLineCol {
|
fn new() -> RunningLineCol {
|
||||||
RunningLineCol {
|
RunningLineCol { line: 0, last_newline: TextUnit::from(0), col_adjust: TextUnit::from(0) }
|
||||||
line: 0,
|
|
||||||
last_newline: TextUnit::from(0),
|
|
||||||
col_adjust: TextUnit::from(0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_line_col(&self, offset: TextUnit) -> LineCol {
|
fn to_line_col(&self, offset: TextUnit) -> LineCol {
|
||||||
|
@ -339,12 +311,7 @@ mod test {
|
||||||
let edited_text = x.edit.apply(&x.text);
|
let edited_text = x.edit.apply(&x.text);
|
||||||
let arb_offset = arb_offset(&edited_text);
|
let arb_offset = arb_offset(&edited_text);
|
||||||
(Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| {
|
(Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| {
|
||||||
ArbTextWithEditAndOffset {
|
ArbTextWithEditAndOffset { text: x.text, edit: x.edit, edited_text, offset }
|
||||||
text: x.text,
|
|
||||||
edit: x.edit,
|
|
||||||
edited_text,
|
|
||||||
offset,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.boxed()
|
.boxed()
|
||||||
|
|
|
@ -70,10 +70,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
|
||||||
node_range: node.syntax().range(),
|
node_range: node.syntax().range(),
|
||||||
kind: node.syntax().kind(),
|
kind: node.syntax().kind(),
|
||||||
detail,
|
detail,
|
||||||
deprecated: node
|
deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"),
|
||||||
.attrs()
|
|
||||||
.filter_map(|x| x.as_named())
|
|
||||||
.any(|x| x == "deprecated"),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,11 +120,9 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
|
||||||
let target_trait = im.target_trait();
|
let target_trait = im.target_trait();
|
||||||
let label = match target_trait {
|
let label = match target_trait {
|
||||||
None => format!("impl {}", target_type.syntax().text()),
|
None => format!("impl {}", target_type.syntax().text()),
|
||||||
Some(t) => format!(
|
Some(t) => {
|
||||||
"impl {} for {}",
|
format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
|
||||||
t.syntax().text(),
|
}
|
||||||
target_type.syntax().text(),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let node = StructureNode {
|
let node = StructureNode {
|
||||||
|
|
|
@ -8,9 +8,8 @@ use ra_syntax::{
|
||||||
use crate::{LocalEdit, TextEditBuilder, formatting::leading_indent};
|
use crate::{LocalEdit, TextEditBuilder, formatting::leading_indent};
|
||||||
|
|
||||||
pub fn on_enter(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> {
|
pub fn on_enter(file: &SourceFile, offset: TextUnit) -> Option<LocalEdit> {
|
||||||
let comment = find_leaf_at_offset(file.syntax(), offset)
|
let comment =
|
||||||
.left_biased()
|
find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(ast::Comment::cast)?;
|
||||||
.and_then(ast::Comment::cast)?;
|
|
||||||
|
|
||||||
if let ast::CommentFlavor::Multiline = comment.flavor() {
|
if let ast::CommentFlavor::Multiline = comment.flavor() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -64,12 +63,7 @@ pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option<LocalEdit>
|
||||||
if expr_range.contains(eq_offset) && eq_offset != expr_range.start() {
|
if expr_range.contains(eq_offset) && eq_offset != expr_range.start() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if file
|
if file.syntax().text().slice(eq_offset..expr_range.start()).contains('\n') {
|
||||||
.syntax()
|
|
||||||
.text()
|
|
||||||
.slice(eq_offset..expr_range.start())
|
|
||||||
.contains('\n')
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -100,10 +94,7 @@ pub fn on_dot_typed(file: &SourceFile, dot_offset: TextUnit) -> Option<LocalEdit
|
||||||
let current_indent_len = TextUnit::of_str(current_indent);
|
let current_indent_len = TextUnit::of_str(current_indent);
|
||||||
|
|
||||||
// Make sure dot is a part of call chain
|
// Make sure dot is a part of call chain
|
||||||
let field_expr = whitespace
|
let field_expr = whitespace.syntax().parent().and_then(ast::FieldExpr::cast)?;
|
||||||
.syntax()
|
|
||||||
.parent()
|
|
||||||
.and_then(ast::FieldExpr::cast)?;
|
|
||||||
let prev_indent = leading_indent(field_expr.syntax())?;
|
let prev_indent = leading_indent(field_expr.syntax())?;
|
||||||
let target_indent = format!(" {}", prev_indent);
|
let target_indent = format!(" {}", prev_indent);
|
||||||
let target_indent_len = TextUnit::of_str(&target_indent);
|
let target_indent_len = TextUnit::of_str(&target_indent);
|
||||||
|
|
|
@ -7,15 +7,13 @@ use lsp_types::{
|
||||||
|
|
||||||
pub fn server_capabilities() -> ServerCapabilities {
|
pub fn server_capabilities() -> ServerCapabilities {
|
||||||
ServerCapabilities {
|
ServerCapabilities {
|
||||||
text_document_sync: Some(TextDocumentSyncCapability::Options(
|
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
|
||||||
TextDocumentSyncOptions {
|
open_close: Some(true),
|
||||||
open_close: Some(true),
|
change: Some(TextDocumentSyncKind::Full),
|
||||||
change: Some(TextDocumentSyncKind::Full),
|
will_save: None,
|
||||||
will_save: None,
|
will_save_wait_until: None,
|
||||||
will_save_wait_until: None,
|
save: None,
|
||||||
save: None,
|
})),
|
||||||
},
|
|
||||||
)),
|
|
||||||
hover_provider: Some(true),
|
hover_provider: Some(true),
|
||||||
completion_provider: Some(CompletionOptions {
|
completion_provider: Some(CompletionOptions {
|
||||||
resolve_provider: None,
|
resolve_provider: None,
|
||||||
|
@ -32,9 +30,7 @@ pub fn server_capabilities() -> ServerCapabilities {
|
||||||
document_symbol_provider: Some(true),
|
document_symbol_provider: Some(true),
|
||||||
workspace_symbol_provider: Some(true),
|
workspace_symbol_provider: Some(true),
|
||||||
code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
|
code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
|
||||||
code_lens_provider: Some(CodeLensOptions {
|
code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
|
||||||
resolve_provider: Some(true),
|
|
||||||
}),
|
|
||||||
document_formatting_provider: Some(true),
|
document_formatting_provider: Some(true),
|
||||||
document_range_formatting_provider: None,
|
document_range_formatting_provider: None,
|
||||||
document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
|
document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
|
||||||
|
|
|
@ -64,10 +64,7 @@ impl CargoTargetSpec {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
let file_id = world.analysis().crate_root(crate_id)?;
|
let file_id = world.analysis().crate_root(crate_id)?;
|
||||||
let path = world
|
let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0.into()));
|
||||||
.vfs
|
|
||||||
.read()
|
|
||||||
.file2path(ra_vfs::VfsFile(file_id.0.into()));
|
|
||||||
let res = world.workspaces.iter().find_map(|ws| {
|
let res = world.workspaces.iter().find_map(|ws| {
|
||||||
let tgt = ws.cargo.target_by_root(&path)?;
|
let tgt = ws.cargo.target_by_root(&path)?;
|
||||||
let res = CargoTargetSpec {
|
let res = CargoTargetSpec {
|
||||||
|
|
|
@ -82,11 +82,8 @@ impl ConvWith for CompletionItem {
|
||||||
fn conv_with(mut self, ctx: &LineIndex) -> ::lsp_types::CompletionItem {
|
fn conv_with(mut self, ctx: &LineIndex) -> ::lsp_types::CompletionItem {
|
||||||
let atom_text_edit = AtomTextEdit::replace(self.source_range(), self.insert_text());
|
let atom_text_edit = AtomTextEdit::replace(self.source_range(), self.insert_text());
|
||||||
let text_edit = (&atom_text_edit).conv_with(ctx);
|
let text_edit = (&atom_text_edit).conv_with(ctx);
|
||||||
let additional_text_edits = if let Some(edit) = self.take_text_edit() {
|
let additional_text_edits =
|
||||||
Some(edit.conv_with(ctx))
|
if let Some(edit) = self.take_text_edit() { Some(edit.conv_with(ctx)) } else { None };
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut res = lsp_types::CompletionItem {
|
let mut res = lsp_types::CompletionItem {
|
||||||
label: self.label().to_string(),
|
label: self.label().to_string(),
|
||||||
|
@ -112,10 +109,7 @@ impl ConvWith for Position {
|
||||||
type Output = TextUnit;
|
type Output = TextUnit;
|
||||||
|
|
||||||
fn conv_with(self, line_index: &LineIndex) -> TextUnit {
|
fn conv_with(self, line_index: &LineIndex) -> TextUnit {
|
||||||
let line_col = LineCol {
|
let line_col = LineCol { line: self.line as u32, col_utf16: self.character as u32 };
|
||||||
line: self.line as u32,
|
|
||||||
col_utf16: self.character as u32,
|
|
||||||
};
|
|
||||||
line_index.offset(line_col)
|
line_index.offset(line_col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,10 +129,7 @@ impl ConvWith for TextRange {
|
||||||
type Output = Range;
|
type Output = Range;
|
||||||
|
|
||||||
fn conv_with(self, line_index: &LineIndex) -> Range {
|
fn conv_with(self, line_index: &LineIndex) -> Range {
|
||||||
Range::new(
|
Range::new(self.start().conv_with(line_index), self.end().conv_with(line_index))
|
||||||
self.start().conv_with(line_index),
|
|
||||||
self.end().conv_with(line_index),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,10 +138,7 @@ impl ConvWith for Range {
|
||||||
type Output = TextRange;
|
type Output = TextRange;
|
||||||
|
|
||||||
fn conv_with(self, line_index: &LineIndex) -> TextRange {
|
fn conv_with(self, line_index: &LineIndex) -> TextRange {
|
||||||
TextRange::from_to(
|
TextRange::from_to(self.start.conv_with(line_index), self.end.conv_with(line_index))
|
||||||
self.start.conv_with(line_index),
|
|
||||||
self.end.conv_with(line_index),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,11 +291,7 @@ impl TryConvWith for SourceChange {
|
||||||
changes: None,
|
changes: None,
|
||||||
document_changes: Some(DocumentChanges::Operations(document_changes)),
|
document_changes: Some(DocumentChanges::Operations(document_changes)),
|
||||||
};
|
};
|
||||||
Ok(req::SourceChange {
|
Ok(req::SourceChange { label: self.label, workspace_edit, cursor_position })
|
||||||
label: self.label,
|
|
||||||
workspace_edit,
|
|
||||||
cursor_position,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,16 +304,8 @@ impl TryConvWith for SourceFileEdit {
|
||||||
version: None,
|
version: None,
|
||||||
};
|
};
|
||||||
let line_index = world.analysis().file_line_index(self.file_id);
|
let line_index = world.analysis().file_line_index(self.file_id);
|
||||||
let edits = self
|
let edits = self.edit.as_atoms().iter().map_conv_with(&line_index).collect();
|
||||||
.edit
|
Ok(TextDocumentEdit { text_document, edits })
|
||||||
.as_atoms()
|
|
||||||
.iter()
|
|
||||||
.map_conv_with(&line_index)
|
|
||||||
.collect();
|
|
||||||
Ok(TextDocumentEdit {
|
|
||||||
text_document,
|
|
||||||
edits,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,18 +318,10 @@ impl TryConvWith for FileSystemEdit {
|
||||||
let uri = world.path_to_uri(source_root, &path)?;
|
let uri = world.path_to_uri(source_root, &path)?;
|
||||||
ResourceOp::Create(CreateFile { uri, options: None })
|
ResourceOp::Create(CreateFile { uri, options: None })
|
||||||
}
|
}
|
||||||
FileSystemEdit::MoveFile {
|
FileSystemEdit::MoveFile { src, dst_source_root, dst_path } => {
|
||||||
src,
|
|
||||||
dst_source_root,
|
|
||||||
dst_path,
|
|
||||||
} => {
|
|
||||||
let old_uri = world.file_id_to_uri(src)?;
|
let old_uri = world.file_id_to_uri(src)?;
|
||||||
let new_uri = world.path_to_uri(dst_source_root, &dst_path)?;
|
let new_uri = world.path_to_uri(dst_source_root, &dst_path)?;
|
||||||
ResourceOp::Rename(RenameFile {
|
ResourceOp::Rename(RenameFile { old_uri, new_uri, options: None })
|
||||||
old_uri,
|
|
||||||
new_uri,
|
|
||||||
options: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -381,11 +349,8 @@ pub fn to_location_link(
|
||||||
|
|
||||||
let target_range = target.info.full_range().conv_with(&tgt_line_index);
|
let target_range = target.info.full_range().conv_with(&tgt_line_index);
|
||||||
|
|
||||||
let target_selection_range = target
|
let target_selection_range =
|
||||||
.info
|
target.info.focus_range().map(|it| it.conv_with(&tgt_line_index)).unwrap_or(target_range);
|
||||||
.focus_range()
|
|
||||||
.map(|it| it.conv_with(&tgt_line_index))
|
|
||||||
.unwrap_or(target_range);
|
|
||||||
|
|
||||||
let res = LocationLink {
|
let res = LocationLink {
|
||||||
origin_selection_range: Some(target.range.conv_with(line_index)),
|
origin_selection_range: Some(target.range.conv_with(line_index)),
|
||||||
|
|
|
@ -36,23 +36,15 @@ struct InitializationOptions {
|
||||||
fn main_inner() -> Result<()> {
|
fn main_inner() -> Result<()> {
|
||||||
let (receiver, sender, threads) = stdio_transport();
|
let (receiver, sender, threads) = stdio_transport();
|
||||||
let cwd = ::std::env::current_dir()?;
|
let cwd = ::std::env::current_dir()?;
|
||||||
run_server(
|
run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| {
|
||||||
ra_lsp_server::server_capabilities(),
|
let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
|
||||||
receiver,
|
let supports_decorations = params
|
||||||
sender,
|
.initialization_options
|
||||||
|params, r, s| {
|
.and_then(|v| InitializationOptions::deserialize(v).ok())
|
||||||
let root = params
|
.and_then(|it| it.publish_decorations)
|
||||||
.root_uri
|
== Some(true);
|
||||||
.and_then(|it| it.to_file_path().ok())
|
ra_lsp_server::main_loop(false, root, supports_decorations, r, s)
|
||||||
.unwrap_or(cwd);
|
})?;
|
||||||
let supports_decorations = params
|
|
||||||
.initialization_options
|
|
||||||
.and_then(|v| InitializationOptions::deserialize(v).ok())
|
|
||||||
.and_then(|it| it.publish_decorations)
|
|
||||||
== Some(true);
|
|
||||||
ra_lsp_server::main_loop(false, root, supports_decorations, r, s)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
log::info!("shutting down IO...");
|
log::info!("shutting down IO...");
|
||||||
threads.join()?;
|
threads.join()?;
|
||||||
log::info!("... IO is down");
|
log::info!("... IO is down");
|
||||||
|
|
|
@ -25,10 +25,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
#[fail(
|
#[fail(display = "Language Server request failed with {}. ({})", code, message)]
|
||||||
display = "Language Server request failed with {}. ({})",
|
|
||||||
code, message
|
|
||||||
)]
|
|
||||||
pub struct LspError {
|
pub struct LspError {
|
||||||
pub code: i32,
|
pub code: i32,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
|
@ -69,9 +66,7 @@ pub fn main_loop(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ws_worker.shutdown();
|
ws_worker.shutdown();
|
||||||
ws_watcher
|
ws_watcher.shutdown().map_err(|_| format_err!("ws watcher died"))?;
|
||||||
.shutdown()
|
|
||||||
.map_err(|_| format_err!("ws watcher died"))?;
|
|
||||||
let mut state = ServerWorldState::new(ws_root.clone(), workspaces);
|
let mut state = ServerWorldState::new(ws_root.clone(), workspaces);
|
||||||
|
|
||||||
log::info!("server initialized, serving requests");
|
log::info!("server initialized, serving requests");
|
||||||
|
@ -92,9 +87,7 @@ pub fn main_loop(
|
||||||
);
|
);
|
||||||
|
|
||||||
log::info!("waiting for tasks to finish...");
|
log::info!("waiting for tasks to finish...");
|
||||||
task_receiver
|
task_receiver.into_iter().for_each(|task| on_task(task, msg_sender, &mut pending_requests));
|
||||||
.into_iter()
|
|
||||||
.for_each(|task| on_task(task, msg_sender, &mut pending_requests));
|
|
||||||
log::info!("...tasks have finished");
|
log::info!("...tasks have finished");
|
||||||
log::info!("joining threadpool...");
|
log::info!("joining threadpool...");
|
||||||
drop(pool);
|
drop(pool);
|
||||||
|
@ -119,9 +112,7 @@ enum Event {
|
||||||
impl fmt::Debug for Event {
|
impl fmt::Debug for Event {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let debug_verbose_not = |not: &RawNotification, f: &mut fmt::Formatter| {
|
let debug_verbose_not = |not: &RawNotification, f: &mut fmt::Formatter| {
|
||||||
f.debug_struct("RawNotification")
|
f.debug_struct("RawNotification").field("method", ¬.method).finish()
|
||||||
.field("method", ¬.method)
|
|
||||||
.finish()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
@ -287,13 +278,7 @@ fn on_request(
|
||||||
sender: &Sender<Task>,
|
sender: &Sender<Task>,
|
||||||
req: RawRequest,
|
req: RawRequest,
|
||||||
) -> Result<Option<RawRequest>> {
|
) -> Result<Option<RawRequest>> {
|
||||||
let mut pool_dispatcher = PoolDispatcher {
|
let mut pool_dispatcher = PoolDispatcher { req: Some(req), res: None, pool, world, sender };
|
||||||
req: Some(req),
|
|
||||||
res: None,
|
|
||||||
pool,
|
|
||||||
world,
|
|
||||||
sender,
|
|
||||||
};
|
|
||||||
let req = pool_dispatcher
|
let req = pool_dispatcher
|
||||||
.on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)?
|
.on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)?
|
||||||
.on::<req::SyntaxTree>(handlers::handle_syntax_tree)?
|
.on::<req::SyntaxTree>(handlers::handle_syntax_tree)?
|
||||||
|
@ -362,13 +347,9 @@ fn on_notification(
|
||||||
let not = match not.cast::<req::DidOpenTextDocument>() {
|
let not = match not.cast::<req::DidOpenTextDocument>() {
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let uri = params.text_document.uri;
|
let uri = params.text_document.uri;
|
||||||
let path = uri
|
let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?;
|
||||||
.to_file_path()
|
if let Some(file_id) =
|
||||||
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
state.vfs.write().add_file_overlay(&path, params.text_document.text)
|
||||||
if let Some(file_id) = state
|
|
||||||
.vfs
|
|
||||||
.write()
|
|
||||||
.add_file_overlay(&path, params.text_document.text)
|
|
||||||
{
|
{
|
||||||
subs.add_sub(FileId(file_id.0.into()));
|
subs.add_sub(FileId(file_id.0.into()));
|
||||||
}
|
}
|
||||||
|
@ -379,14 +360,9 @@ fn on_notification(
|
||||||
let not = match not.cast::<req::DidChangeTextDocument>() {
|
let not = match not.cast::<req::DidChangeTextDocument>() {
|
||||||
Ok(mut params) => {
|
Ok(mut params) => {
|
||||||
let uri = params.text_document.uri;
|
let uri = params.text_document.uri;
|
||||||
let path = uri
|
let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?;
|
||||||
.to_file_path()
|
let text =
|
||||||
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
params.content_changes.pop().ok_or_else(|| format_err!("empty changes"))?.text;
|
||||||
let text = params
|
|
||||||
.content_changes
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| format_err!("empty changes"))?
|
|
||||||
.text;
|
|
||||||
state.vfs.write().change_file_overlay(path.as_path(), text);
|
state.vfs.write().change_file_overlay(path.as_path(), text);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -395,16 +371,11 @@ fn on_notification(
|
||||||
let not = match not.cast::<req::DidCloseTextDocument>() {
|
let not = match not.cast::<req::DidCloseTextDocument>() {
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let uri = params.text_document.uri;
|
let uri = params.text_document.uri;
|
||||||
let path = uri
|
let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?;
|
||||||
.to_file_path()
|
|
||||||
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
|
||||||
if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
|
if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
|
||||||
subs.remove_sub(FileId(file_id.0.into()));
|
subs.remove_sub(FileId(file_id.0.into()));
|
||||||
}
|
}
|
||||||
let params = req::PublishDiagnosticsParams {
|
let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() };
|
||||||
uri,
|
|
||||||
diagnostics: Vec::new(),
|
|
||||||
};
|
|
||||||
let not = RawNotification::new::<req::PublishDiagnostics>(¶ms);
|
let not = RawNotification::new::<req::PublishDiagnostics>(¶ms);
|
||||||
msg_sender.send(RawMessage::Notification(not)).unwrap();
|
msg_sender.send(RawMessage::Notification(not)).unwrap();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
@ -46,12 +46,7 @@ pub fn handle_extend_selection(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map_conv_with(&line_index)
|
.map_conv_with(&line_index)
|
||||||
.map(|range| FileRange { file_id, range })
|
.map(|range| FileRange { file_id, range })
|
||||||
.map(|frange| {
|
.map(|frange| world.analysis().extend_selection(frange).map(|it| it.conv_with(&line_index)))
|
||||||
world
|
|
||||||
.analysis()
|
|
||||||
.extend_selection(frange)
|
|
||||||
.map(|it| it.conv_with(&line_index))
|
|
||||||
})
|
|
||||||
.collect::<Cancelable<Vec<_>>>()?;
|
.collect::<Cancelable<Vec<_>>>()?;
|
||||||
Ok(req::ExtendSelectionResult { selections })
|
Ok(req::ExtendSelectionResult { selections })
|
||||||
}
|
}
|
||||||
|
@ -67,10 +62,7 @@ pub fn handle_find_matching_brace(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map_conv_with(&line_index)
|
.map_conv_with(&line_index)
|
||||||
.map(|offset| {
|
.map(|offset| {
|
||||||
world
|
world.analysis().matching_brace(FilePosition { file_id, offset }).unwrap_or(offset)
|
||||||
.analysis()
|
|
||||||
.matching_brace(FilePosition { file_id, offset })
|
|
||||||
.unwrap_or(offset)
|
|
||||||
})
|
})
|
||||||
.map_conv_with(&line_index)
|
.map_conv_with(&line_index)
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -171,11 +163,7 @@ pub fn handle_workspace_symbol(
|
||||||
let all_symbols = params.query.contains('#');
|
let all_symbols = params.query.contains('#');
|
||||||
let libs = params.query.contains('*');
|
let libs = params.query.contains('*');
|
||||||
let query = {
|
let query = {
|
||||||
let query: String = params
|
let query: String = params.query.chars().filter(|&c| c != '#' && c != '*').collect();
|
||||||
.query
|
|
||||||
.chars()
|
|
||||||
.filter(|&c| c != '#' && c != '*')
|
|
||||||
.collect();
|
|
||||||
let mut q = Query::new(query);
|
let mut q = Query::new(query);
|
||||||
if !all_symbols {
|
if !all_symbols {
|
||||||
q.only_types();
|
q.only_types();
|
||||||
|
@ -367,10 +355,7 @@ pub fn handle_completion(
|
||||||
Some(items) => items,
|
Some(items) => items,
|
||||||
};
|
};
|
||||||
let line_index = world.analysis().file_line_index(position.file_id);
|
let line_index = world.analysis().file_line_index(position.file_id);
|
||||||
let items = items
|
let items = items.into_iter().map(|item| item.conv_with(&line_index)).collect();
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.conv_with(&line_index))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(Some(req::CompletionResponse::Array(items)))
|
Ok(Some(req::CompletionResponse::Array(items)))
|
||||||
}
|
}
|
||||||
|
@ -496,9 +481,8 @@ pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option<
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let optional_change = world
|
let optional_change =
|
||||||
.analysis()
|
world.analysis().rename(FilePosition { file_id, offset }, &*params.new_name)?;
|
||||||
.rename(FilePosition { file_id, offset }, &*params.new_name)?;
|
|
||||||
let change = match optional_change {
|
let change = match optional_change {
|
||||||
None => return Ok(None),
|
None => return Ok(None),
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
|
@ -517,14 +501,10 @@ pub fn handle_references(
|
||||||
let line_index = world.analysis().file_line_index(file_id);
|
let line_index = world.analysis().file_line_index(file_id);
|
||||||
let offset = params.position.conv_with(&line_index);
|
let offset = params.position.conv_with(&line_index);
|
||||||
|
|
||||||
let refs = world
|
let refs = world.analysis().find_all_refs(FilePosition { file_id, offset })?;
|
||||||
.analysis()
|
|
||||||
.find_all_refs(FilePosition { file_id, offset })?;
|
|
||||||
|
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
refs.into_iter()
|
refs.into_iter().filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok()).collect(),
|
||||||
.filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
|
|
||||||
.collect(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,9 +520,7 @@ pub fn handle_formatting(
|
||||||
|
|
||||||
use std::process;
|
use std::process;
|
||||||
let mut rustfmt = process::Command::new("rustfmt");
|
let mut rustfmt = process::Command::new("rustfmt");
|
||||||
rustfmt
|
rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped());
|
||||||
.stdin(process::Stdio::piped())
|
|
||||||
.stdout(process::Stdio::piped());
|
|
||||||
|
|
||||||
if let Ok(path) = params.text_document.uri.to_file_path() {
|
if let Ok(path) = params.text_document.uri.to_file_path() {
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
|
@ -582,10 +560,7 @@ pub fn handle_code_action(
|
||||||
let line_index = world.analysis().file_line_index(file_id);
|
let line_index = world.analysis().file_line_index(file_id);
|
||||||
let range = params.range.conv_with(&line_index);
|
let range = params.range.conv_with(&line_index);
|
||||||
|
|
||||||
let assists = world
|
let assists = world.analysis().assists(FileRange { file_id, range })?.into_iter();
|
||||||
.analysis()
|
|
||||||
.assists(FileRange { file_id, range })?
|
|
||||||
.into_iter();
|
|
||||||
let fixes = world
|
let fixes = world
|
||||||
.analysis()
|
.analysis()
|
||||||
.diagnostics(file_id)?
|
.diagnostics(file_id)?
|
||||||
|
@ -720,18 +695,11 @@ pub fn handle_code_lens_resolve(world: ServerWorld, code_lens: CodeLens) -> Resu
|
||||||
to_value(locations).unwrap(),
|
to_value(locations).unwrap(),
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
Ok(CodeLens {
|
Ok(CodeLens { range: code_lens.range, command: Some(cmd), data: None })
|
||||||
range: code_lens.range,
|
|
||||||
command: Some(cmd),
|
|
||||||
data: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
None => Ok(CodeLens {
|
None => Ok(CodeLens {
|
||||||
range: code_lens.range,
|
range: code_lens.range,
|
||||||
command: Some(Command {
|
command: Some(Command { title: "Error".into(), ..Default::default() }),
|
||||||
title: "Error".into(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
data: None,
|
data: None,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -744,16 +712,11 @@ pub fn handle_document_highlight(
|
||||||
let file_id = params.text_document.try_conv_with(&world)?;
|
let file_id = params.text_document.try_conv_with(&world)?;
|
||||||
let line_index = world.analysis().file_line_index(file_id);
|
let line_index = world.analysis().file_line_index(file_id);
|
||||||
|
|
||||||
let refs = world
|
let refs = world.analysis().find_all_refs(params.try_conv_with(&world)?)?;
|
||||||
.analysis()
|
|
||||||
.find_all_refs(params.try_conv_with(&world)?)?;
|
|
||||||
|
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
refs.into_iter()
|
refs.into_iter()
|
||||||
.map(|r| DocumentHighlight {
|
.map(|r| DocumentHighlight { range: r.1.conv_with(&line_index), kind: None })
|
||||||
range: r.1.conv_with(&line_index),
|
|
||||||
kind: None,
|
|
||||||
})
|
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -785,10 +748,7 @@ pub fn publish_decorations(
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
) -> Result<req::PublishDecorationsParams> {
|
) -> Result<req::PublishDecorationsParams> {
|
||||||
let uri = world.file_id_to_uri(file_id)?;
|
let uri = world.file_id_to_uri(file_id)?;
|
||||||
Ok(req::PublishDecorationsParams {
|
Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? })
|
||||||
uri,
|
|
||||||
decorations: highlight(&world, file_id)?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
|
fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
|
||||||
|
@ -797,10 +757,7 @@ fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
|
||||||
.analysis()
|
.analysis()
|
||||||
.highlight(file_id)?
|
.highlight(file_id)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|h| Decoration {
|
.map(|h| Decoration { range: h.range.conv_with(&line_index), tag: h.tag })
|
||||||
range: h.range.conv_with(&line_index),
|
|
||||||
tag: h.tag,
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,7 @@ pub struct Subscriptions {
|
||||||
|
|
||||||
impl Subscriptions {
|
impl Subscriptions {
|
||||||
pub fn new() -> Subscriptions {
|
pub fn new() -> Subscriptions {
|
||||||
Subscriptions {
|
Subscriptions { subs: FxHashSet::default() }
|
||||||
subs: FxHashSet::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn add_sub(&mut self, file_id: FileId) {
|
pub fn add_sub(&mut self, file_id: FileId) {
|
||||||
self.subs.insert(file_id);
|
self.subs.insert(file_id);
|
||||||
|
|
|
@ -118,14 +118,11 @@ impl Target {
|
||||||
impl CargoWorkspace {
|
impl CargoWorkspace {
|
||||||
pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
|
pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
|
||||||
let mut meta = MetadataCommand::new();
|
let mut meta = MetadataCommand::new();
|
||||||
meta.manifest_path(cargo_toml)
|
meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures);
|
||||||
.features(CargoOpt::AllFeatures);
|
|
||||||
if let Some(parent) = cargo_toml.parent() {
|
if let Some(parent) = cargo_toml.parent() {
|
||||||
meta.current_dir(parent);
|
meta.current_dir(parent);
|
||||||
}
|
}
|
||||||
let meta = meta
|
let meta = meta.exec().map_err(|e| format_err!("cargo metadata failed: {}", e))?;
|
||||||
.exec()
|
|
||||||
.map_err(|e| format_err!("cargo metadata failed: {}", e))?;
|
|
||||||
let mut pkg_by_id = FxHashMap::default();
|
let mut pkg_by_id = FxHashMap::default();
|
||||||
let mut packages = Arena::default();
|
let mut packages = Arena::default();
|
||||||
let mut targets = Arena::default();
|
let mut targets = Arena::default();
|
||||||
|
@ -157,10 +154,8 @@ impl CargoWorkspace {
|
||||||
for node in resolve.nodes {
|
for node in resolve.nodes {
|
||||||
let source = pkg_by_id[&node.id];
|
let source = pkg_by_id[&node.id];
|
||||||
for dep_node in node.deps {
|
for dep_node in node.deps {
|
||||||
let dep = PackageDependency {
|
let dep =
|
||||||
name: dep_node.name.into(),
|
PackageDependency { name: dep_node.name.into(), pkg: pkg_by_id[&dep_node.pkg] };
|
||||||
pkg: pkg_by_id[&dep_node.pkg],
|
|
||||||
};
|
|
||||||
packages[source].dependencies.push(dep);
|
packages[source].dependencies.push(dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,8 +166,6 @@ impl CargoWorkspace {
|
||||||
self.packages.iter().map(|(id, _pkg)| id)
|
self.packages.iter().map(|(id, _pkg)| id)
|
||||||
}
|
}
|
||||||
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
|
pub fn target_by_root(&self, root: &Path) -> Option<Target> {
|
||||||
self.packages()
|
self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next()
|
||||||
.filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
|
|
||||||
.next()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,7 @@ impl Sysroot {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sysroot = Sysroot {
|
let mut sysroot = Sysroot { crates: Arena::default() };
|
||||||
crates: Arena::default(),
|
|
||||||
};
|
|
||||||
for name in SYSROOT_CRATES.trim().lines() {
|
for name in SYSROOT_CRATES.trim().lines() {
|
||||||
let root = src.join(format!("lib{}", name)).join("lib.rs");
|
let root = src.join(format!("lib{}", name)).join("lib.rs");
|
||||||
if root.exists() {
|
if root.exists() {
|
||||||
|
@ -77,10 +75,7 @@ impl Sysroot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
||||||
self.crates
|
self.crates.iter().find(|(_id, data)| data.name == name).map(|(id, _data)| id)
|
||||||
.iter()
|
|
||||||
.find(|(_id, data)| data.name == name)
|
|
||||||
.map(|(id, _data)| id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,10 +80,7 @@ impl ServerWorldState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let libstd = ws
|
let libstd = ws.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it));
|
||||||
.sysroot
|
|
||||||
.std()
|
|
||||||
.and_then(|it| sysroot_crates.get(&it).map(|&it| it));
|
|
||||||
|
|
||||||
let mut pkg_to_lib_crate = FxHashMap::default();
|
let mut pkg_to_lib_crate = FxHashMap::default();
|
||||||
let mut pkg_crates = FxHashMap::default();
|
let mut pkg_crates = FxHashMap::default();
|
||||||
|
@ -99,10 +96,7 @@ impl ServerWorldState {
|
||||||
lib_tgt = Some(crate_id);
|
lib_tgt = Some(crate_id);
|
||||||
pkg_to_lib_crate.insert(pkg, crate_id);
|
pkg_to_lib_crate.insert(pkg, crate_id);
|
||||||
}
|
}
|
||||||
pkg_crates
|
pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
|
||||||
.entry(pkg)
|
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push(crate_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,18 +186,8 @@ impl ServerWorldState {
|
||||||
libs.push((SourceRootId(root.0.into()), files));
|
libs.push((SourceRootId(root.0.into()), files));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VfsChange::AddFile {
|
VfsChange::AddFile { root, file, path, text } => {
|
||||||
root,
|
change.add_file(SourceRootId(root.0.into()), FileId(file.0.into()), path, text);
|
||||||
file,
|
|
||||||
path,
|
|
||||||
text,
|
|
||||||
} => {
|
|
||||||
change.add_file(
|
|
||||||
SourceRootId(root.0.into()),
|
|
||||||
FileId(file.0.into()),
|
|
||||||
path,
|
|
||||||
text,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
VfsChange::RemoveFile { root, file, path } => {
|
VfsChange::RemoveFile { root, file, path } => {
|
||||||
change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path)
|
change.remove_file(SourceRootId(root.0.into()), FileId(file.0.into()), path)
|
||||||
|
@ -247,9 +231,7 @@ impl ServerWorld {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
|
pub fn uri_to_file_id(&self, uri: &Url) -> Result<FileId> {
|
||||||
let path = uri
|
let path = uri.to_file_path().map_err(|()| format_err!("invalid uri: {}", uri))?;
|
||||||
.to_file_path()
|
|
||||||
.map_err(|()| format_err!("invalid uri: {}", uri))?;
|
|
||||||
let file = self
|
let file = self
|
||||||
.vfs
|
.vfs
|
||||||
.read()
|
.read()
|
||||||
|
|
|
@ -55,10 +55,7 @@ fn foo() {
|
||||||
);
|
);
|
||||||
server.wait_for_feedback("workspace loaded");
|
server.wait_for_feedback("workspace loaded");
|
||||||
server.request::<Runnables>(
|
server.request::<Runnables>(
|
||||||
RunnablesParams {
|
RunnablesParams { text_document: server.doc_id("lib.rs"), position: None },
|
||||||
text_document: server.doc_id("lib.rs"),
|
|
||||||
position: None,
|
|
||||||
},
|
|
||||||
json!([
|
json!([
|
||||||
{
|
{
|
||||||
"args": [ "test", "--", "foo", "--nocapture" ],
|
"args": [ "test", "--", "foo", "--nocapture" ],
|
||||||
|
@ -220,10 +217,7 @@ fn main() {}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
server.wait_for_feedback("workspace loaded");
|
server.wait_for_feedback("workspace loaded");
|
||||||
let empty_context = || CodeActionContext {
|
let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None };
|
||||||
diagnostics: Vec::new(),
|
|
||||||
only: None,
|
|
||||||
};
|
|
||||||
server.request::<CodeActionRequest>(
|
server.request::<CodeActionRequest>(
|
||||||
CodeActionParams {
|
CodeActionParams {
|
||||||
text_document: server.doc_id("src/lib.rs"),
|
text_document: server.doc_id("src/lib.rs"),
|
||||||
|
|
|
@ -83,9 +83,7 @@ impl Server {
|
||||||
|
|
||||||
pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
|
pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
|
||||||
let path = self.dir.path().join(rel_path);
|
let path = self.dir.path().join(rel_path);
|
||||||
TextDocumentIdentifier {
|
TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
|
||||||
uri: Url::from_file_path(path).unwrap(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request<R>(&self, params: R::Params, expected_resp: Value)
|
pub fn request<R>(&self, params: R::Params, expected_resp: Value)
|
||||||
|
@ -119,11 +117,7 @@ impl Server {
|
||||||
}
|
}
|
||||||
fn send_request_(&self, r: RawRequest) -> Value {
|
fn send_request_(&self, r: RawRequest) -> Value {
|
||||||
let id = r.id;
|
let id = r.id;
|
||||||
self.worker
|
self.worker.as_ref().unwrap().send(RawMessage::Request(r)).unwrap();
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.send(RawMessage::Request(r))
|
|
||||||
.unwrap();
|
|
||||||
while let Some(msg) = self.recv() {
|
while let Some(msg) = self.recv() {
|
||||||
match msg {
|
match msg {
|
||||||
RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
|
RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
|
||||||
|
@ -169,11 +163,7 @@ impl Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn send_notification(&self, not: RawNotification) {
|
fn send_notification(&self, not: RawNotification) {
|
||||||
self.worker
|
self.worker.as_ref().unwrap().send(RawMessage::Notification(not)).unwrap();
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.send(RawMessage::Notification(not))
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,18 +137,12 @@ impl_froms!(TokenTree: Leaf, Subtree);
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let source_file = ast::SourceFile::parse(macro_definition);
|
let source_file = ast::SourceFile::parse(macro_definition);
|
||||||
let macro_definition = source_file
|
let macro_definition =
|
||||||
.syntax()
|
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
||||||
.descendants()
|
|
||||||
.find_map(ast::MacroCall::cast)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let source_file = ast::SourceFile::parse(macro_invocation);
|
let source_file = ast::SourceFile::parse(macro_invocation);
|
||||||
let macro_invocation = source_file
|
let macro_invocation =
|
||||||
.syntax()
|
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
||||||
.descendants()
|
|
||||||
.find_map(ast::MacroCall::cast)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
|
let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
|
||||||
let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
|
let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
|
||||||
|
@ -163,11 +157,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
|
||||||
|
|
||||||
fn create_rules(macro_definition: &str) -> MacroRules {
|
fn create_rules(macro_definition: &str) -> MacroRules {
|
||||||
let source_file = ast::SourceFile::parse(macro_definition);
|
let source_file = ast::SourceFile::parse(macro_definition);
|
||||||
let macro_definition = source_file
|
let macro_definition =
|
||||||
.syntax()
|
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
||||||
.descendants()
|
|
||||||
.find_map(ast::MacroCall::cast)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
|
let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
|
||||||
crate::MacroRules::parse(&definition_tt).unwrap()
|
crate::MacroRules::parse(&definition_tt).unwrap()
|
||||||
|
@ -175,11 +166,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
|
||||||
|
|
||||||
fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
|
fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
|
||||||
let source_file = ast::SourceFile::parse(invocation);
|
let source_file = ast::SourceFile::parse(invocation);
|
||||||
let macro_invocation = source_file
|
let macro_invocation =
|
||||||
.syntax()
|
source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
|
||||||
.descendants()
|
|
||||||
.find_map(ast::MacroCall::cast)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
|
let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -133,11 +133,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Option<Bindings>
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
crate::TokenTree::Repeat(crate::Repeat {
|
crate::TokenTree::Repeat(crate::Repeat { subtree, kind: _, separator }) => {
|
||||||
subtree,
|
|
||||||
kind: _,
|
|
||||||
separator,
|
|
||||||
}) => {
|
|
||||||
while let Some(nested) = match_lhs(subtree, input) {
|
while let Some(nested) = match_lhs(subtree, input) {
|
||||||
res.push_nested(nested)?;
|
res.push_nested(nested)?;
|
||||||
if let Some(separator) = *separator {
|
if let Some(separator) = *separator {
|
||||||
|
@ -166,10 +162,7 @@ fn expand_subtree(
|
||||||
.map(|it| expand_tt(it, bindings, nesting))
|
.map(|it| expand_tt(it, bindings, nesting))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
|
|
||||||
Some(tt::Subtree {
|
Some(tt::Subtree { token_trees, delimiter: template.delimiter })
|
||||||
token_trees,
|
|
||||||
delimiter: template.delimiter,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_tt(
|
fn expand_tt(
|
||||||
|
@ -188,23 +181,15 @@ fn expand_tt(
|
||||||
token_trees.push(t.into())
|
token_trees.push(t.into())
|
||||||
}
|
}
|
||||||
nesting.pop().unwrap();
|
nesting.pop().unwrap();
|
||||||
tt::Subtree {
|
tt::Subtree { token_trees, delimiter: tt::Delimiter::None }.into()
|
||||||
token_trees,
|
|
||||||
delimiter: tt::Delimiter::None,
|
|
||||||
}
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
crate::TokenTree::Leaf(leaf) => match leaf {
|
crate::TokenTree::Leaf(leaf) => match leaf {
|
||||||
crate::Leaf::Ident(ident) => tt::Leaf::from(tt::Ident {
|
crate::Leaf::Ident(ident) => {
|
||||||
text: ident.text.clone(),
|
tt::Leaf::from(tt::Ident { text: ident.text.clone() }).into()
|
||||||
})
|
}
|
||||||
.into(),
|
|
||||||
crate::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(),
|
crate::Leaf::Punct(punct) => tt::Leaf::from(punct.clone()).into(),
|
||||||
crate::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(),
|
crate::Leaf::Var(v) => bindings.get(&v.text, nesting)?.clone(),
|
||||||
crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal {
|
crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(),
|
||||||
text: l.text.clone(),
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
|
|
@ -52,10 +52,7 @@ fn parse_subtree(tt: &tt::Subtree) -> Option<crate::Subtree> {
|
||||||
};
|
};
|
||||||
token_trees.push(child);
|
token_trees.push(child);
|
||||||
}
|
}
|
||||||
Some(crate::Subtree {
|
Some(crate::Subtree { token_trees, delimiter: tt.delimiter })
|
||||||
token_trees,
|
|
||||||
delimiter: tt.delimiter,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_var(p: &mut TtCursor) -> Option<crate::Var> {
|
fn parse_var(p: &mut TtCursor) -> Option<crate::Var> {
|
||||||
|
@ -92,9 +89,5 @@ fn parse_repeat(p: &mut TtCursor) -> Option<crate::Repeat> {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
p.bump();
|
p.bump();
|
||||||
Some(crate::Repeat {
|
Some(crate::Repeat { subtree, kind, separator })
|
||||||
subtree,
|
|
||||||
kind,
|
|
||||||
separator,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,23 +23,14 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
|
||||||
for char in child.leaf_text().unwrap().chars() {
|
for char in child.leaf_text().unwrap().chars() {
|
||||||
if let Some(char) = prev {
|
if let Some(char) = prev {
|
||||||
token_trees.push(
|
token_trees.push(
|
||||||
tt::Leaf::from(tt::Punct {
|
tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Joint }).into(),
|
||||||
char,
|
|
||||||
spacing: tt::Spacing::Joint,
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
prev = Some(char)
|
prev = Some(char)
|
||||||
}
|
}
|
||||||
if let Some(char) = prev {
|
if let Some(char) = prev {
|
||||||
token_trees.push(
|
token_trees
|
||||||
tt::Leaf::from(tt::Punct {
|
.push(tt::Leaf::from(tt::Punct { char, spacing: tt::Spacing::Alone }).into());
|
||||||
char,
|
|
||||||
spacing: tt::Spacing::Alone,
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let child: tt::TokenTree = if child.kind() == TOKEN_TREE {
|
let child: tt::TokenTree = if child.kind() == TOKEN_TREE {
|
||||||
|
@ -48,10 +39,7 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
|
||||||
let text = child.leaf_text().unwrap().clone();
|
let text = child.leaf_text().unwrap().clone();
|
||||||
tt::Leaf::from(tt::Ident { text }).into()
|
tt::Leaf::from(tt::Ident { text }).into()
|
||||||
} else if child.kind().is_literal() {
|
} else if child.kind().is_literal() {
|
||||||
tt::Leaf::from(tt::Literal {
|
tt::Leaf::from(tt::Literal { text: child.leaf_text().unwrap().clone() }).into()
|
||||||
text: child.leaf_text().unwrap().clone(),
|
|
||||||
})
|
|
||||||
.into()
|
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
@ -59,9 +47,6 @@ fn convert_tt(tt: &SyntaxNode) -> Option<tt::Subtree> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = tt::Subtree {
|
let res = tt::Subtree { delimiter, token_trees };
|
||||||
delimiter,
|
|
||||||
token_trees,
|
|
||||||
};
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,7 @@ pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> {
|
pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> {
|
||||||
EmptyVisitorCtx {
|
EmptyVisitorCtx { ph: PhantomData, ctx }
|
||||||
ph: PhantomData,
|
|
||||||
ctx,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Visitor<'a>: Sized {
|
pub trait Visitor<'a>: Sized {
|
||||||
|
@ -21,11 +18,7 @@ pub trait Visitor<'a>: Sized {
|
||||||
N: AstNode + 'a,
|
N: AstNode + 'a,
|
||||||
F: FnOnce(&'a N) -> Self::Output,
|
F: FnOnce(&'a N) -> Self::Output,
|
||||||
{
|
{
|
||||||
Vis {
|
Vis { inner: self, f, ph: PhantomData }
|
||||||
inner: self,
|
|
||||||
f,
|
|
||||||
ph: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,11 +31,7 @@ pub trait VisitorCtx<'a>: Sized {
|
||||||
N: AstNode + 'a,
|
N: AstNode + 'a,
|
||||||
F: FnOnce(&'a N, Self::Ctx) -> Self::Output,
|
F: FnOnce(&'a N, Self::Ctx) -> Self::Output,
|
||||||
{
|
{
|
||||||
VisCtx {
|
VisCtx { inner: self, f, ph: PhantomData }
|
||||||
inner: self,
|
|
||||||
f,
|
|
||||||
ph: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,16 +127,12 @@ pub trait DocCommentsOwner: AstNode {
|
||||||
let line = comment.text().as_str();
|
let line = comment.text().as_str();
|
||||||
|
|
||||||
// Determine if the prefix or prefix + 1 char is stripped
|
// Determine if the prefix or prefix + 1 char is stripped
|
||||||
let pos = if line
|
let pos =
|
||||||
.chars()
|
if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) {
|
||||||
.nth(prefix_len)
|
prefix_len + 1
|
||||||
.map(|c| c.is_whitespace())
|
} else {
|
||||||
.unwrap_or(false)
|
prefix_len
|
||||||
{
|
};
|
||||||
prefix_len + 1
|
|
||||||
} else {
|
|
||||||
prefix_len
|
|
||||||
};
|
|
||||||
|
|
||||||
line[pos..].to_owned()
|
line[pos..].to_owned()
|
||||||
})
|
})
|
||||||
|
@ -357,10 +353,7 @@ pub enum PathSegmentKind<'a> {
|
||||||
|
|
||||||
impl PathSegment {
|
impl PathSegment {
|
||||||
pub fn parent_path(&self) -> &Path {
|
pub fn parent_path(&self) -> &Path {
|
||||||
self.syntax()
|
self.syntax().parent().and_then(Path::cast).expect("segments are always nested in paths")
|
||||||
.parent()
|
|
||||||
.and_then(Path::cast)
|
|
||||||
.expect("segments are always nested in paths")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> Option<PathSegmentKind> {
|
pub fn kind(&self) -> Option<PathSegmentKind> {
|
||||||
|
@ -428,10 +421,7 @@ pub struct AstChildren<'a, N> {
|
||||||
|
|
||||||
impl<'a, N> AstChildren<'a, N> {
|
impl<'a, N> AstChildren<'a, N> {
|
||||||
fn new(parent: &'a SyntaxNode) -> Self {
|
fn new(parent: &'a SyntaxNode) -> Self {
|
||||||
AstChildren {
|
AstChildren { inner: parent.children(), ph: PhantomData }
|
||||||
inner: parent.children(),
|
|
||||||
ph: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,11 +648,7 @@ impl SelfParam {
|
||||||
let borrowed = self.syntax().children().any(|n| n.kind() == AMP);
|
let borrowed = self.syntax().children().any(|n| n.kind() == AMP);
|
||||||
if borrowed {
|
if borrowed {
|
||||||
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
|
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
|
||||||
if self
|
if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW)
|
||||||
.syntax()
|
|
||||||
.children()
|
|
||||||
.skip_while(|n| n.kind() != AMP)
|
|
||||||
.any(|n| n.kind() == MUT_KW)
|
|
||||||
{
|
{
|
||||||
SelfParamFlavor::MutRef
|
SelfParamFlavor::MutRef
|
||||||
} else {
|
} else {
|
||||||
|
@ -769,8 +755,5 @@ fn test_doc_comment_preserves_indents() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
|
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
|
||||||
assert_eq!(
|
assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap());
|
||||||
"doc1\n```\nfn foo() {\n // ...\n}\n```",
|
|
||||||
module.doc_comment_text().unwrap()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,26 +7,17 @@ use super::*;
|
||||||
const EXPR_FIRST: TokenSet = LHS_FIRST;
|
const EXPR_FIRST: TokenSet = LHS_FIRST;
|
||||||
|
|
||||||
pub(super) fn expr(p: &mut Parser) -> BlockLike {
|
pub(super) fn expr(p: &mut Parser) -> BlockLike {
|
||||||
let r = Restrictions {
|
let r = Restrictions { forbid_structs: false, prefer_stmt: false };
|
||||||
forbid_structs: false,
|
|
||||||
prefer_stmt: false,
|
|
||||||
};
|
|
||||||
expr_bp(p, r, 1)
|
expr_bp(p, r, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
|
pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
|
||||||
let r = Restrictions {
|
let r = Restrictions { forbid_structs: false, prefer_stmt: true };
|
||||||
forbid_structs: false,
|
|
||||||
prefer_stmt: true,
|
|
||||||
};
|
|
||||||
expr_bp(p, r, 1)
|
expr_bp(p, r, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_no_struct(p: &mut Parser) {
|
fn expr_no_struct(p: &mut Parser) {
|
||||||
let r = Restrictions {
|
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
|
||||||
forbid_structs: true,
|
|
||||||
prefer_stmt: false,
|
|
||||||
};
|
|
||||||
expr_bp(p, r, 1);
|
expr_bp(p, r, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,14 +141,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.expect(R_PAREN);
|
p.expect(R_PAREN);
|
||||||
m.complete(
|
m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
|
||||||
p,
|
|
||||||
if saw_expr && !saw_comma {
|
|
||||||
PAREN_EXPR
|
|
||||||
} else {
|
|
||||||
TUPLE_EXPR
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test array_expr
|
// test array_expr
|
||||||
|
|
|
@ -155,11 +155,7 @@ pub(super) fn maybe_item(p: &mut Parser, flavor: ItemFlavor) -> MaybeItem {
|
||||||
IMPL_BLOCK
|
IMPL_BLOCK
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return if has_mods {
|
return if has_mods { MaybeItem::Modifiers } else { MaybeItem::None };
|
||||||
MaybeItem::Modifiers
|
|
||||||
} else {
|
|
||||||
MaybeItem::None
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,7 @@ impl Flavor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_(p: &mut Parser, flavor: Flavor) {
|
fn list_(p: &mut Parser, flavor: Flavor) {
|
||||||
let (bra, ket) = if flavor.type_required() {
|
let (bra, ket) = if flavor.type_required() { (L_PAREN, R_PAREN) } else { (PIPE, PIPE) };
|
||||||
(L_PAREN, R_PAREN)
|
|
||||||
} else {
|
|
||||||
(PIPE, PIPE)
|
|
||||||
};
|
|
||||||
assert!(p.at(bra));
|
assert!(p.at(bra));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump();
|
p.bump();
|
||||||
|
|
|
@ -2,9 +2,7 @@ use super::*;
|
||||||
|
|
||||||
pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
|
pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
|
||||||
.union(paths::PATH_FIRST)
|
.union(paths::PATH_FIRST)
|
||||||
.union(token_set![
|
.union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE]);
|
||||||
REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE
|
|
||||||
]);
|
|
||||||
|
|
||||||
pub(super) fn pattern(p: &mut Parser) {
|
pub(super) fn pattern(p: &mut Parser) {
|
||||||
pattern_r(p, PAT_RECOVERY_SET)
|
pattern_r(p, PAT_RECOVERY_SET)
|
||||||
|
|
|
@ -11,10 +11,7 @@ pub(crate) struct Ptr<'s> {
|
||||||
impl<'s> Ptr<'s> {
|
impl<'s> Ptr<'s> {
|
||||||
/// Creates a new `Ptr` from a string.
|
/// Creates a new `Ptr` from a string.
|
||||||
pub fn new(text: &'s str) -> Ptr<'s> {
|
pub fn new(text: &'s str) -> Ptr<'s> {
|
||||||
Ptr {
|
Ptr { text, len: 0.into() }
|
||||||
text,
|
|
||||||
len: 0.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the length of the remaining string.
|
/// Gets the length of the remaining string.
|
||||||
|
|
|
@ -11,11 +11,7 @@
|
||||||
//! [rfc#2256]: <https://github.com/rust-lang/rfcs/pull/2256>
|
//! [rfc#2256]: <https://github.com/rust-lang/rfcs/pull/2256>
|
||||||
//! [RFC.md]: <https://github.com/matklad/libsyntax2/blob/master/docs/RFC.md>
|
//! [RFC.md]: <https://github.com/matklad/libsyntax2/blob/master/docs/RFC.md>
|
||||||
|
|
||||||
#![forbid(
|
#![forbid(missing_debug_implementations, unconditional_recursion, future_incompatible)]
|
||||||
missing_debug_implementations,
|
|
||||||
unconditional_recursion,
|
|
||||||
future_incompatible
|
|
||||||
)]
|
|
||||||
#![deny(bad_style, missing_docs)]
|
#![deny(bad_style, missing_docs)]
|
||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
//#![warn(unreachable_pub)] // rust-lang/rust#47816
|
//#![warn(unreachable_pub)] // rust-lang/rust#47816
|
||||||
|
@ -70,8 +66,7 @@ impl SourceFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> {
|
pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> {
|
||||||
self.incremental_reparse(edit)
|
self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
|
||||||
.unwrap_or_else(|| self.full_reparse(edit))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> {
|
pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> {
|
||||||
|
|
|
@ -136,10 +136,7 @@ pub(crate) struct Marker {
|
||||||
|
|
||||||
impl Marker {
|
impl Marker {
|
||||||
fn new(pos: u32) -> Marker {
|
fn new(pos: u32) -> Marker {
|
||||||
Marker {
|
Marker { pos, bomb: DropBomb::new("Marker must be either completed or abandoned") }
|
||||||
pos,
|
|
||||||
bomb: DropBomb::new("Marker must be either completed or abandoned"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finishes the syntax tree node and assigns `kind` to it,
|
/// Finishes the syntax tree node and assigns `kind` to it,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue