mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Reformat all
This commit is contained in:
parent
857c1650ef
commit
6be50f7d5d
35 changed files with 423 additions and 367 deletions
|
@ -1,22 +1,22 @@
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use ra_editor::find_node_at_offset;
|
||||||
use ra_editor::{find_node_at_offset};
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
AtomEdit, File, TextUnit, AstNode, SyntaxNodeRef,
|
|
||||||
algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx},
|
algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx},
|
||||||
ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner},
|
ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner},
|
||||||
|
AstNode, AtomEdit, File,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
|
SyntaxNodeRef, TextUnit,
|
||||||
};
|
};
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FileId, Cancelable,
|
|
||||||
input::FilesDatabase,
|
|
||||||
db::{self, SyntaxDatabase},
|
db::{self, SyntaxDatabase},
|
||||||
descriptors::DescriptorDatabase,
|
|
||||||
descriptors::function::FnScopes,
|
descriptors::function::FnScopes,
|
||||||
descriptors::module::{ModuleTree, ModuleId, ModuleScope},
|
descriptors::module::{ModuleId, ModuleScope, ModuleTree},
|
||||||
|
descriptors::DescriptorDatabase,
|
||||||
|
input::FilesDatabase,
|
||||||
|
Cancelable, FileId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CompletionItem {
|
pub struct CompletionItem {
|
||||||
/// What user sees in pop-up
|
/// What user sees in pop-up
|
||||||
|
@ -27,7 +27,11 @@ pub struct CompletionItem {
|
||||||
pub snippet: Option<String>,
|
pub snippet: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
|
pub(crate) fn resolve_based_completion(
|
||||||
|
db: &db::RootDatabase,
|
||||||
|
file_id: FileId,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Cancelable<Option<Vec<CompletionItem>>> {
|
||||||
let source_root_id = db.file_source_root(file_id);
|
let source_root_id = db.file_source_root(file_id);
|
||||||
let file = db.file_syntax(file_id);
|
let file = db.file_syntax(file_id);
|
||||||
let module_tree = db.module_tree(source_root_id)?;
|
let module_tree = db.module_tree(source_root_id)?;
|
||||||
|
@ -56,9 +60,12 @@ pub(crate) fn resolve_based_completion(db: &db::RootDatabase, file_id: FileId, o
|
||||||
Ok(Some(res))
|
Ok(Some(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn find_target_module(
|
||||||
|
module_tree: &ModuleTree,
|
||||||
pub(crate) fn find_target_module(module_tree: &ModuleTree, module_id: ModuleId, file: &File, offset: TextUnit) -> Option<ModuleId> {
|
module_id: ModuleId,
|
||||||
|
file: &File,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Option<ModuleId> {
|
||||||
let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset)?;
|
let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset)?;
|
||||||
let mut crate_path = crate_path(name_ref)?;
|
let mut crate_path = crate_path(name_ref)?;
|
||||||
|
|
||||||
|
@ -71,8 +78,10 @@ pub(crate) fn find_target_module(module_tree: &ModuleTree, module_id: ModuleId,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
|
fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
|
||||||
let mut path = name_ref.syntax()
|
let mut path = name_ref
|
||||||
.parent().and_then(ast::PathSegment::cast)?
|
.syntax()
|
||||||
|
.parent()
|
||||||
|
.and_then(ast::PathSegment::cast)?
|
||||||
.parent_path();
|
.parent_path();
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
|
@ -80,8 +89,7 @@ fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
|
||||||
match segment.kind()? {
|
match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => res.push(name),
|
ast::PathSegmentKind::Name(name) => res.push(name),
|
||||||
ast::PathSegmentKind::CrateKw => break,
|
ast::PathSegmentKind::CrateKw => break,
|
||||||
ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw =>
|
ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
|
||||||
return None,
|
|
||||||
}
|
}
|
||||||
path = path.qualifier()?;
|
path = path.qualifier()?;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +97,6 @@ fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn scope_completion(
|
pub(crate) fn scope_completion(
|
||||||
db: &db::RootDatabase,
|
db: &db::RootDatabase,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
|
@ -158,11 +165,7 @@ fn complete_module_items(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_name_ref(
|
fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
|
||||||
file: &File,
|
|
||||||
name_ref: ast::NameRef,
|
|
||||||
acc: &mut Vec<CompletionItem>,
|
|
||||||
) {
|
|
||||||
if !is_node::<ast::Path>(name_ref.syntax()) {
|
if !is_node::<ast::Path>(name_ref.syntax()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +276,11 @@ fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
|
||||||
.visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
|
.visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
|
||||||
.accept(node);
|
.accept(node);
|
||||||
if let Some(Some(body)) = loop_body {
|
if let Some(Some(body)) = loop_body {
|
||||||
if name_ref.syntax().range().is_subrange(&body.syntax().range()) {
|
if name_ref
|
||||||
|
.syntax()
|
||||||
|
.range()
|
||||||
|
.is_subrange(&body.syntax().range())
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,9 +375,9 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use test_utils::{assert_eq_dbg};
|
use test_utils::assert_eq_dbg;
|
||||||
|
|
||||||
use crate::mock_analysis::{single_file_with_position};
|
use crate::mock_analysis::single_file_with_position;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use std::{
|
use std::sync::Arc;
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use ra_editor::LineIndex;
|
use ra_editor::LineIndex;
|
||||||
use ra_syntax::File;
|
use ra_syntax::File;
|
||||||
|
@ -8,14 +6,13 @@ use salsa;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db,
|
db,
|
||||||
Cancelable, Canceled,
|
|
||||||
descriptors::{
|
descriptors::{
|
||||||
DescriptorDatabase, SubmodulesQuery, ModuleTreeQuery, ModuleScopeQuery,
|
DescriptorDatabase, FnScopesQuery, FnSyntaxQuery, ModuleScopeQuery, ModuleTreeQuery,
|
||||||
FnSyntaxQuery, FnScopesQuery
|
SubmodulesQuery,
|
||||||
},
|
},
|
||||||
symbol_index::SymbolIndex,
|
symbol_index::SymbolIndex,
|
||||||
syntax_ptr::{SyntaxPtrDatabase, ResolveSyntaxPtrQuery},
|
syntax_ptr::{ResolveSyntaxPtrQuery, SyntaxPtrDatabase},
|
||||||
FileId,
|
Cancelable, Canceled, FileId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::ast::{AstNode, FnDef, FnDefNode};
|
||||||
ast::{AstNode, FnDef, FnDefNode},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::descriptors::{
|
||||||
descriptors::{
|
|
||||||
DescriptorDatabase,
|
|
||||||
function::{FnId, FnScopes},
|
function::{FnId, FnScopes},
|
||||||
},
|
DescriptorDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
/// Resolve `FnId` to the corresponding `SyntaxNode`
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
pub(super) mod imp;
|
pub(super) mod imp;
|
||||||
mod scope;
|
mod scope;
|
||||||
|
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{max, min};
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
||||||
TextRange, TextUnit
|
TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{syntax_ptr::SyntaxPtr, FileId};
|
||||||
FileId,
|
|
||||||
syntax_ptr::SyntaxPtr
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) use self::scope::{FnScopes, resolve_local_name};
|
|
||||||
|
|
||||||
|
pub(crate) use self::scope::{resolve_local_name, FnScopes};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct FnId(SyntaxPtr);
|
pub(crate) struct FnId(SyntaxPtr);
|
||||||
|
@ -26,14 +22,13 @@ impl FnId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FnDescriptor {
|
pub struct FnDescriptor {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub ret_type: Option<String>,
|
pub ret_type: Option<String>,
|
||||||
pub params: Vec<String>,
|
pub params: Vec<String>,
|
||||||
pub doc: Option<String>
|
pub doc: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnDescriptor {
|
impl FnDescriptor {
|
||||||
|
@ -57,7 +52,9 @@ impl FnDescriptor {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((comment_range, docs)) = FnDescriptor::extract_doc_comments(node) {
|
if let Some((comment_range, docs)) = FnDescriptor::extract_doc_comments(node) {
|
||||||
let comment_range = comment_range.checked_sub(node.syntax().range().start()).unwrap();
|
let comment_range = comment_range
|
||||||
|
.checked_sub(node.syntax().range().start())
|
||||||
|
.unwrap();
|
||||||
let start = comment_range.start().to_usize();
|
let start = comment_range.start().to_usize();
|
||||||
let end = comment_range.end().to_usize();
|
let end = comment_range.end().to_usize();
|
||||||
|
|
||||||
|
@ -94,7 +91,7 @@ impl FnDescriptor {
|
||||||
ret_type,
|
ret_type,
|
||||||
params,
|
params,
|
||||||
label: label.trim().to_owned(),
|
label: label.trim().to_owned(),
|
||||||
doc
|
doc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +102,13 @@ impl FnDescriptor {
|
||||||
|
|
||||||
let comment_text = node.doc_comment_text();
|
let comment_text = node.doc_comment_text();
|
||||||
|
|
||||||
let (begin, end) = node.doc_comments()
|
let (begin, end) = node
|
||||||
|
.doc_comments()
|
||||||
.map(|comment| comment.syntax().range())
|
.map(|comment| comment.syntax().range())
|
||||||
.map(|range| (range.start().to_usize(), range.end().to_usize()))
|
.map(|range| (range.start().to_usize(), range.end().to_usize()))
|
||||||
.fold((std::usize::MAX, std::usize::MIN), |acc, range| (min(acc.0, range.0), max(acc.1, range.1)));
|
.fold((std::usize::MAX, std::usize::MIN), |acc, range| {
|
||||||
|
(min(acc.0, range.0), max(acc.1, range.1))
|
||||||
|
});
|
||||||
|
|
||||||
let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));
|
let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));
|
||||||
|
|
||||||
|
@ -134,4 +134,3 @@ impl FnDescriptor {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,9 +51,7 @@ impl FnScopes {
|
||||||
&self.get(scope).entries
|
&self.get(scope).entries
|
||||||
}
|
}
|
||||||
pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
|
pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
|
||||||
generate(self.scope_for(node), move |&scope| {
|
generate(self.scope_for(node), move |&scope| self.get(scope).parent)
|
||||||
self.get(scope).parent
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
fn root_scope(&mut self) -> ScopeId {
|
fn root_scope(&mut self) -> ScopeId {
|
||||||
let res = ScopeId(self.scopes.len() as u32);
|
let res = ScopeId(self.scopes.len() as u32);
|
||||||
|
@ -273,13 +271,12 @@ pub fn resolve_local_name<'a>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ra_editor::find_node_at_offset;
|
||||||
use ra_syntax::File;
|
use ra_syntax::File;
|
||||||
use test_utils::extract_offset;
|
use test_utils::extract_offset;
|
||||||
use ra_editor::{find_node_at_offset};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
fn do_check(code: &str, expected: &[&str]) {
|
fn do_check(code: &str, expected: &[&str]) {
|
||||||
let (off, code) = extract_offset(code);
|
let (off, code) = extract_offset(code);
|
||||||
let code = {
|
let code = {
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
pub(crate) mod module;
|
|
||||||
pub(crate) mod function;
|
pub(crate) mod function;
|
||||||
|
pub(crate) mod module;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
SmolStr,
|
|
||||||
ast::{self, AstNode, FnDefNode},
|
ast::{self, AstNode, FnDefNode},
|
||||||
TextRange
|
SmolStr, TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FileId, Cancelable,
|
|
||||||
db::SyntaxDatabase,
|
db::SyntaxDatabase,
|
||||||
descriptors::module::{ModuleTree, ModuleId, ModuleScope},
|
descriptors::function::{resolve_local_name, FnId, FnScopes},
|
||||||
descriptors::function::{FnId, FnScopes, resolve_local_name},
|
descriptors::module::{ModuleId, ModuleScope, ModuleTree},
|
||||||
input::SourceRootId,
|
input::SourceRootId,
|
||||||
syntax_ptr::{SyntaxPtrDatabase, LocalSyntaxPtr},
|
syntax_ptr::{LocalSyntaxPtr, SyntaxPtrDatabase},
|
||||||
|
Cancelable, FileId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
salsa::query_group! {
|
salsa::query_group! {
|
||||||
pub(crate) trait DescriptorDatabase: SyntaxDatabase + SyntaxPtrDatabase {
|
pub(crate) trait DescriptorDatabase: SyntaxDatabase + SyntaxPtrDatabase {
|
||||||
fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
|
fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
|
||||||
|
@ -49,23 +47,20 @@ salsa::query_group! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReferenceDescriptor {
|
pub struct ReferenceDescriptor {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
pub name: String
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeclarationDescriptor<'a> {
|
pub struct DeclarationDescriptor<'a> {
|
||||||
pat: ast::BindPat<'a>,
|
pat: ast::BindPat<'a>,
|
||||||
pub range: TextRange
|
pub range: TextRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeclarationDescriptor<'a> {
|
impl<'a> DeclarationDescriptor<'a> {
|
||||||
pub fn new(pat: ast::BindPat) -> DeclarationDescriptor {
|
pub fn new(pat: ast::BindPat) -> DeclarationDescriptor {
|
||||||
let range = pat.syntax().range();
|
let range = pat.syntax().range();
|
||||||
|
|
||||||
DeclarationDescriptor {
|
DeclarationDescriptor { pat, range }
|
||||||
pat,
|
|
||||||
range
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> {
|
pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> {
|
||||||
|
@ -73,22 +68,22 @@ impl<'a> DeclarationDescriptor<'a> {
|
||||||
|
|
||||||
let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) {
|
let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) {
|
||||||
Some(def) => def,
|
Some(def) => def,
|
||||||
None => return Default::default()
|
None => return Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_scopes = FnScopes::new(fn_def);
|
let fn_scopes = FnScopes::new(fn_def);
|
||||||
|
|
||||||
let refs : Vec<_> = fn_def.syntax().descendants()
|
let refs: Vec<_> = fn_def
|
||||||
|
.syntax()
|
||||||
|
.descendants()
|
||||||
.filter_map(ast::NameRef::cast)
|
.filter_map(ast::NameRef::cast)
|
||||||
.filter(|name_ref| {
|
.filter(|name_ref| match resolve_local_name(*name_ref, &fn_scopes) {
|
||||||
match resolve_local_name(*name_ref, &fn_scopes) {
|
|
||||||
None => false,
|
None => false,
|
||||||
Some(entry) => entry.ptr() == name_ptr,
|
Some(entry) => entry.ptr() == name_ptr,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.map(|name_ref| ReferenceDescriptor {
|
.map(|name_ref| ReferenceDescriptor {
|
||||||
name: name_ref.syntax().text().to_string(),
|
name: name_ref.syntax().text().to_string(),
|
||||||
range : name_ref.syntax().range(),
|
range: name_ref.syntax().range(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ra_syntax::{
|
||||||
|
ast::{self, NameOwner},
|
||||||
|
SmolStr,
|
||||||
|
};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use ra_syntax::{
|
|
||||||
SmolStr,
|
|
||||||
ast::{self, NameOwner},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
FileId, Cancelable, FileResolverImp, db,
|
db,
|
||||||
input::{SourceRoot, SourceRootId},
|
|
||||||
descriptors::DescriptorDatabase,
|
descriptors::DescriptorDatabase,
|
||||||
|
input::{SourceRoot, SourceRootId},
|
||||||
|
Cancelable, FileId, FileResolverImp,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleTree, Problem};
|
||||||
ModuleData, ModuleTree, ModuleId, LinkId, LinkData, Problem, ModuleScope
|
|
||||||
};
|
|
||||||
|
|
||||||
|
pub(crate) fn submodules(
|
||||||
pub(crate) fn submodules(db: &impl DescriptorDatabase, file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> {
|
db: &impl DescriptorDatabase,
|
||||||
|
file_id: FileId,
|
||||||
|
) -> Cancelable<Arc<Vec<SmolStr>>> {
|
||||||
db::check_canceled(db)?;
|
db::check_canceled(db)?;
|
||||||
let file = db.file_syntax(file_id);
|
let file = db.file_syntax(file_id);
|
||||||
let root = file.ast();
|
let root = file.ast();
|
||||||
|
@ -57,13 +58,11 @@ pub(crate) fn module_tree(
|
||||||
Ok(Arc::new(res))
|
Ok(Arc::new(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
|
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
|
||||||
pub struct Submodule {
|
pub struct Submodule {
|
||||||
pub name: SmolStr,
|
pub name: SmolStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn create_module_tree<'a>(
|
fn create_module_tree<'a>(
|
||||||
db: &impl DescriptorDatabase,
|
db: &impl DescriptorDatabase,
|
||||||
source_root: SourceRootId,
|
source_root: SourceRootId,
|
||||||
|
@ -82,7 +81,15 @@ fn create_module_tree<'a>(
|
||||||
continue; // TODO: use explicit crate_roots here
|
continue; // TODO: use explicit crate_roots here
|
||||||
}
|
}
|
||||||
assert!(!roots.contains_key(&file_id));
|
assert!(!roots.contains_key(&file_id));
|
||||||
let module_id = build_subtree(db, &source_root, &mut tree, &mut visited, &mut roots, None, file_id)?;
|
let module_id = build_subtree(
|
||||||
|
db,
|
||||||
|
&source_root,
|
||||||
|
&mut tree,
|
||||||
|
&mut visited,
|
||||||
|
&mut roots,
|
||||||
|
None,
|
||||||
|
file_id,
|
||||||
|
)?;
|
||||||
roots.insert(file_id, module_id);
|
roots.insert(file_id, module_id);
|
||||||
}
|
}
|
||||||
Ok(tree)
|
Ok(tree)
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
pub(super) mod imp;
|
pub(super) mod imp;
|
||||||
pub(crate) mod scope;
|
pub(crate) mod scope;
|
||||||
|
|
||||||
|
use ra_syntax::{
|
||||||
|
ast::{self, AstNode, NameOwner},
|
||||||
|
SmolStr, SyntaxNode,
|
||||||
|
};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode};
|
|
||||||
|
|
||||||
use crate::FileId;
|
use crate::FileId;
|
||||||
|
|
||||||
|
@ -16,9 +19,11 @@ pub(crate) struct ModuleTree {
|
||||||
|
|
||||||
impl ModuleTree {
|
impl ModuleTree {
|
||||||
pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec<ModuleId> {
|
pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec<ModuleId> {
|
||||||
self.mods.iter()
|
self.mods
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(|(_idx, it)| it.file_id == file_id).map(|(idx, _)| ModuleId(idx as u32))
|
.filter(|(_idx, it)| it.file_id == file_id)
|
||||||
|
.map(|(idx, _)| ModuleId(idx as u32))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,18 +74,15 @@ impl ModuleId {
|
||||||
curr
|
curr
|
||||||
}
|
}
|
||||||
pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> {
|
pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> {
|
||||||
let link = tree.module(self)
|
let link = tree
|
||||||
|
.module(self)
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&it| tree.link(it))
|
.map(|&it| tree.link(it))
|
||||||
.find(|it| it.name == name)?;
|
.find(|it| it.name == name)?;
|
||||||
Some(*link.points_to.first()?)
|
Some(*link.points_to.first()?)
|
||||||
}
|
}
|
||||||
pub(crate) fn problems(
|
pub(crate) fn problems(self, tree: &ModuleTree, root: ast::Root) -> Vec<(SyntaxNode, Problem)> {
|
||||||
self,
|
|
||||||
tree: &ModuleTree,
|
|
||||||
root: ast::Root,
|
|
||||||
) -> Vec<(SyntaxNode, Problem)> {
|
|
||||||
tree.module(self)
|
tree.module(self)
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -98,11 +100,7 @@ impl LinkId {
|
||||||
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
|
pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
|
||||||
tree.link(self).owner
|
tree.link(self).owner
|
||||||
}
|
}
|
||||||
pub(crate) fn bind_source<'a>(
|
pub(crate) fn bind_source<'a>(self, tree: &ModuleTree, root: ast::Root<'a>) -> ast::Module<'a> {
|
||||||
self,
|
|
||||||
tree: &ModuleTree,
|
|
||||||
root: ast::Root<'a>,
|
|
||||||
) -> ast::Module<'a> {
|
|
||||||
imp::modules(root)
|
imp::modules(root)
|
||||||
.find(|(name, _)| name == &tree.link(self).name)
|
.find(|(name, _)| name == &tree.link(self).name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -125,7 +123,6 @@ struct LinkData {
|
||||||
problem: Option<Problem>,
|
problem: Option<Problem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ModuleTree {
|
impl ModuleTree {
|
||||||
fn module(&self, id: ModuleId) -> &ModuleData {
|
fn module(&self, id: ModuleId) -> &ModuleData {
|
||||||
&self.mods[id.0 as usize]
|
&self.mods[id.0 as usize]
|
||||||
|
@ -152,4 +149,3 @@ impl ModuleTree {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
//! Backend for module-level scope resolution & completion
|
//! Backend for module-level scope resolution & completion
|
||||||
|
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, ModuleItemOwner},
|
ast::{self, ModuleItemOwner},
|
||||||
File, AstNode, SmolStr,
|
AstNode, File, SmolStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::syntax_ptr::LocalSyntaxPtr;
|
use crate::syntax_ptr::LocalSyntaxPtr;
|
||||||
|
@ -103,7 +102,7 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ra_syntax::{File};
|
use ra_syntax::File;
|
||||||
|
|
||||||
fn do_check(code: &str, expected: &[&str]) {
|
fn do_check(code: &str, expected: &[&str]) {
|
||||||
let file = File::parse(&code);
|
let file = File::parse(&code);
|
||||||
|
|
|
@ -13,24 +13,21 @@ use ra_syntax::{
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use relative_path::RelativePath;
|
use relative_path::RelativePath;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use salsa::{ParallelDatabase, Database};
|
use salsa::{Database, ParallelDatabase};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnalysisChange,
|
completion::{resolve_based_completion, scope_completion, CompletionItem},
|
||||||
db::{
|
db::{self, FileSyntaxQuery, SyntaxDatabase},
|
||||||
self, SyntaxDatabase, FileSyntaxQuery,
|
|
||||||
},
|
|
||||||
input::{SourceRootId, FilesDatabase, SourceRoot, WORKSPACE},
|
|
||||||
descriptors::{
|
descriptors::{
|
||||||
DescriptorDatabase, DeclarationDescriptor,
|
|
||||||
module::{ModuleTree, Problem},
|
|
||||||
function::{FnDescriptor, FnId},
|
function::{FnDescriptor, FnId},
|
||||||
|
module::{ModuleTree, Problem},
|
||||||
|
DeclarationDescriptor, DescriptorDatabase,
|
||||||
},
|
},
|
||||||
completion::{scope_completion, resolve_based_completion, CompletionItem},
|
input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
|
||||||
symbol_index::SymbolIndex,
|
symbol_index::SymbolIndex,
|
||||||
syntax_ptr::SyntaxPtrDatabase,
|
syntax_ptr::SyntaxPtrDatabase,
|
||||||
CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position,
|
AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver,
|
||||||
Query, SourceChange, SourceFileEdit, Cancelable,
|
FileSystemEdit, Position, Query, SourceChange, SourceFileEdit,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -94,7 +91,6 @@ pub(crate) struct AnalysisHostImpl {
|
||||||
db: db::RootDatabase,
|
db: db::RootDatabase,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AnalysisHostImpl {
|
impl AnalysisHostImpl {
|
||||||
pub fn new() -> AnalysisHostImpl {
|
pub fn new() -> AnalysisHostImpl {
|
||||||
let db = db::RootDatabase::default();
|
let db = db::RootDatabase::default();
|
||||||
|
@ -108,7 +104,7 @@ impl AnalysisHostImpl {
|
||||||
}
|
}
|
||||||
pub fn analysis(&self) -> AnalysisImpl {
|
pub fn analysis(&self) -> AnalysisImpl {
|
||||||
AnalysisImpl {
|
AnalysisImpl {
|
||||||
db: self.db.fork() // freeze revision here
|
db: self.db.fork(), // freeze revision here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn apply_change(&mut self, change: AnalysisChange) {
|
pub fn apply_change(&mut self, change: AnalysisChange) {
|
||||||
|
@ -120,7 +116,8 @@ impl AnalysisHostImpl {
|
||||||
.set(file_id, Arc::new(text))
|
.set(file_id, Arc::new(text))
|
||||||
}
|
}
|
||||||
if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
|
if !(change.files_added.is_empty() && change.files_removed.is_empty()) {
|
||||||
let file_resolver = change.file_resolver
|
let file_resolver = change
|
||||||
|
.file_resolver
|
||||||
.expect("change resolver when changing set of files");
|
.expect("change resolver when changing set of files");
|
||||||
let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
|
let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE));
|
||||||
for (file_id, text) in change.files_added {
|
for (file_id, text) in change.files_added {
|
||||||
|
@ -174,7 +171,8 @@ impl AnalysisHostImpl {
|
||||||
.set((), Arc::new(libraries));
|
.set((), Arc::new(libraries));
|
||||||
}
|
}
|
||||||
if let Some(crate_graph) = change.crate_graph {
|
if let Some(crate_graph) = change.crate_graph {
|
||||||
self.db.query(crate::input::CrateGraphQuery)
|
self.db
|
||||||
|
.query(crate::input::CrateGraphQuery)
|
||||||
.set((), Arc::new(crate_graph))
|
.set((), Arc::new(crate_graph))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,18 +192,22 @@ impl AnalysisImpl {
|
||||||
}
|
}
|
||||||
pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||||
let buf: Vec<Arc<SymbolIndex>> = if query.libs {
|
let buf: Vec<Arc<SymbolIndex>> = if query.libs {
|
||||||
self.db.libraries().iter()
|
self.db
|
||||||
|
.libraries()
|
||||||
|
.iter()
|
||||||
.map(|&lib_id| self.db.library_symbols(lib_id))
|
.map(|&lib_id| self.db.library_symbols(lib_id))
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let files = &self.db.source_root(WORKSPACE).files;
|
let files = &self.db.source_root(WORKSPACE).files;
|
||||||
let db = self.db.clone();
|
let db = self.db.clone();
|
||||||
files.par_iter()
|
files
|
||||||
|
.par_iter()
|
||||||
.map_with(db, |db, &file_id| db.file_symbols(file_id))
|
.map_with(db, |db, &file_id| db.file_symbols(file_id))
|
||||||
.filter_map(|it| it.ok())
|
.filter_map(|it| it.ok())
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
self.db.query(FileSyntaxQuery)
|
self.db
|
||||||
|
.query(FileSyntaxQuery)
|
||||||
.sweep(salsa::SweepStrategy::default().discard_values());
|
.sweep(salsa::SweepStrategy::default().discard_values());
|
||||||
Ok(query.search(&buf))
|
Ok(query.search(&buf))
|
||||||
}
|
}
|
||||||
|
@ -216,7 +218,8 @@ impl AnalysisImpl {
|
||||||
pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||||
let module_tree = self.module_tree(file_id)?;
|
let module_tree = self.module_tree(file_id)?;
|
||||||
|
|
||||||
let res = module_tree.modules_for_file(file_id)
|
let res = module_tree
|
||||||
|
.modules_for_file(file_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|module_id| {
|
.filter_map(|module_id| {
|
||||||
let link = module_id.parent_link(&module_tree)?;
|
let link = module_id.parent_link(&module_tree)?;
|
||||||
|
@ -237,7 +240,8 @@ impl AnalysisImpl {
|
||||||
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
|
||||||
let module_tree = self.module_tree(file_id)?;
|
let module_tree = self.module_tree(file_id)?;
|
||||||
let crate_graph = self.db.crate_graph();
|
let crate_graph = self.db.crate_graph();
|
||||||
let res = module_tree.modules_for_file(file_id)
|
let res = module_tree
|
||||||
|
.modules_for_file(file_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|it| it.root(&module_tree))
|
.map(|it| it.root(&module_tree))
|
||||||
.map(|it| it.file_id(&module_tree))
|
.map(|it| it.file_id(&module_tree))
|
||||||
|
@ -249,7 +253,11 @@ impl AnalysisImpl {
|
||||||
pub fn crate_root(&self, crate_id: CrateId) -> FileId {
|
pub fn crate_root(&self, crate_id: CrateId) -> FileId {
|
||||||
self.db.crate_graph().crate_roots[&crate_id]
|
self.db.crate_graph().crate_roots[&crate_id]
|
||||||
}
|
}
|
||||||
pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
|
pub fn completions(
|
||||||
|
&self,
|
||||||
|
file_id: FileId,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Cancelable<Option<Vec<CompletionItem>>> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut has_completions = false;
|
let mut has_completions = false;
|
||||||
if let Some(scope_based) = scope_completion(&self.db, file_id, offset) {
|
if let Some(scope_based) = scope_completion(&self.db, file_id, offset) {
|
||||||
|
@ -260,11 +268,7 @@ impl AnalysisImpl {
|
||||||
res.extend(scope_based);
|
res.extend(scope_based);
|
||||||
has_completions = true;
|
has_completions = true;
|
||||||
}
|
}
|
||||||
let res = if has_completions {
|
let res = if has_completions { Some(res) } else { None };
|
||||||
Some(res)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
pub fn approximately_resolve_symbol(
|
pub fn approximately_resolve_symbol(
|
||||||
|
@ -326,8 +330,7 @@ impl AnalysisImpl {
|
||||||
let syntax = file.syntax();
|
let syntax = file.syntax();
|
||||||
|
|
||||||
// Find the binding associated with the offset
|
// Find the binding associated with the offset
|
||||||
let maybe_binding = find_node_at_offset::<ast::BindPat>(syntax, offset)
|
let maybe_binding = find_node_at_offset::<ast::BindPat>(syntax, offset).or_else(|| {
|
||||||
.or_else(|| {
|
|
||||||
let name_ref = find_node_at_offset::<ast::NameRef>(syntax, offset)?;
|
let name_ref = find_node_at_offset::<ast::NameRef>(syntax, offset)?;
|
||||||
let resolved = resolve_local_name(&self.db, file_id, name_ref)?;
|
let resolved = resolve_local_name(&self.db, file_id, name_ref)?;
|
||||||
find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end())
|
find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end())
|
||||||
|
@ -341,8 +344,11 @@ impl AnalysisImpl {
|
||||||
let decl = DeclarationDescriptor::new(binding);
|
let decl = DeclarationDescriptor::new(binding);
|
||||||
|
|
||||||
let mut ret = vec![(file_id, decl.range)];
|
let mut ret = vec![(file_id, decl.range)];
|
||||||
ret.extend(decl.find_all_refs().into_iter()
|
ret.extend(
|
||||||
.map(|ref_desc| (file_id, ref_desc.range )));
|
decl.find_all_refs()
|
||||||
|
.into_iter()
|
||||||
|
.map(|ref_desc| (file_id, ref_desc.range)),
|
||||||
|
);
|
||||||
|
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
@ -526,7 +532,8 @@ impl AnalysisImpl {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => return Vec::new(),
|
None => return Vec::new(),
|
||||||
};
|
};
|
||||||
module_id.child(module_tree, name.as_str())
|
module_id
|
||||||
|
.child(module_tree, name.as_str())
|
||||||
.map(|it| it.file_id(module_tree))
|
.map(|it| it.file_id(module_tree))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
use std::{
|
use std::{fmt, sync::Arc};
|
||||||
sync::Arc,
|
|
||||||
fmt,
|
|
||||||
};
|
|
||||||
|
|
||||||
use salsa;
|
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use relative_path::RelativePath;
|
use relative_path::RelativePath;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
use salsa;
|
||||||
|
|
||||||
use crate::{symbol_index::SymbolIndex, FileResolverImp};
|
use crate::{symbol_index::SymbolIndex, FileResolverImp};
|
||||||
|
|
||||||
|
|
|
@ -6,23 +6,20 @@ extern crate relative_path;
|
||||||
extern crate rustc_hash;
|
extern crate rustc_hash;
|
||||||
extern crate salsa;
|
extern crate salsa;
|
||||||
|
|
||||||
mod input;
|
mod completion;
|
||||||
mod db;
|
mod db;
|
||||||
mod descriptors;
|
mod descriptors;
|
||||||
mod imp;
|
mod imp;
|
||||||
mod symbol_index;
|
mod input;
|
||||||
mod completion;
|
|
||||||
mod syntax_ptr;
|
|
||||||
pub mod mock_analysis;
|
pub mod mock_analysis;
|
||||||
|
mod symbol_index;
|
||||||
|
mod syntax_ptr;
|
||||||
|
|
||||||
use std::{
|
use std::{fmt, sync::Arc};
|
||||||
fmt,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
|
use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
|
||||||
use relative_path::RelativePathBuf;
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp},
|
imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp},
|
||||||
|
@ -30,13 +27,12 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
descriptors::function::FnDescriptor,
|
|
||||||
completion::CompletionItem,
|
completion::CompletionItem,
|
||||||
input::{FileId, FileResolver, CrateGraph, CrateId},
|
descriptors::function::FnDescriptor,
|
||||||
|
input::{CrateGraph, CrateId, FileId, FileResolver},
|
||||||
};
|
};
|
||||||
pub use ra_editor::{
|
pub use ra_editor::{
|
||||||
FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable,
|
FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode,
|
||||||
RunnableKind, StructureNode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
@ -50,8 +46,7 @@ impl std::fmt::Display for Canceled {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Canceled {
|
impl std::error::Error for Canceled {}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct AnalysisChange {
|
pub struct AnalysisChange {
|
||||||
|
@ -76,7 +71,6 @@ impl fmt::Debug for AnalysisChange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl AnalysisChange {
|
impl AnalysisChange {
|
||||||
pub fn new() -> AnalysisChange {
|
pub fn new() -> AnalysisChange {
|
||||||
AnalysisChange::default()
|
AnalysisChange::default()
|
||||||
|
@ -251,12 +245,15 @@ impl Analysis {
|
||||||
pub fn approximately_resolve_symbol(
|
pub fn approximately_resolve_symbol(
|
||||||
&self,
|
&self,
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
offset: TextUnit
|
offset: TextUnit,
|
||||||
) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||||
self.imp
|
self.imp.approximately_resolve_symbol(file_id, offset)
|
||||||
.approximately_resolve_symbol(file_id, offset)
|
|
||||||
}
|
}
|
||||||
pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, ) -> Cancelable<Vec<(FileId, TextRange)>> {
|
pub fn find_all_refs(
|
||||||
|
&self,
|
||||||
|
file_id: FileId,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Cancelable<Vec<(FileId, TextRange)>> {
|
||||||
Ok(self.imp.find_all_refs(file_id, offset))
|
Ok(self.imp.find_all_refs(file_id, offset))
|
||||||
}
|
}
|
||||||
pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
|
||||||
|
@ -276,7 +273,11 @@ impl Analysis {
|
||||||
let file = self.imp.file_syntax(file_id);
|
let file = self.imp.file_syntax(file_id);
|
||||||
Ok(ra_editor::highlight(&file))
|
Ok(ra_editor::highlight(&file))
|
||||||
}
|
}
|
||||||
pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
|
pub fn completions(
|
||||||
|
&self,
|
||||||
|
file_id: FileId,
|
||||||
|
offset: TextUnit,
|
||||||
|
) -> Cancelable<Option<Vec<CompletionItem>>> {
|
||||||
self.imp.completions(file_id, offset)
|
self.imp.completions(file_id, offset)
|
||||||
}
|
}
|
||||||
pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> {
|
pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> {
|
||||||
|
@ -307,7 +308,11 @@ impl LibraryData {
|
||||||
let file = File::parse(text);
|
let file = File::parse(text);
|
||||||
(*file_id, file)
|
(*file_id, file)
|
||||||
}));
|
}));
|
||||||
LibraryData { files, file_resolver: FileResolverImp::new(file_resolver), symbol_index }
|
LibraryData {
|
||||||
|
files,
|
||||||
|
file_resolver: FileResolverImp::new(file_resolver),
|
||||||
|
symbol_index,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use relative_path::{RelativePath, RelativePathBuf};
|
|
||||||
use ra_syntax::TextUnit;
|
use ra_syntax::TextUnit;
|
||||||
|
use relative_path::{RelativePath, RelativePathBuf};
|
||||||
use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
|
use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
|
||||||
|
|
||||||
use crate::{
|
use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FileResolver};
|
||||||
AnalysisChange, Analysis, AnalysisHost, FileId, FileResolver,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FilePosition {
|
pub struct FilePosition {
|
||||||
|
@ -51,7 +48,10 @@ 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!(position.is_none(), "only one marker (<|>) per fixture is allowed");
|
assert!(
|
||||||
|
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);
|
||||||
|
@ -73,7 +73,10 @@ impl MockAnalysis {
|
||||||
FilePosition { file_id, offset }
|
FilePosition { file_id, offset }
|
||||||
}
|
}
|
||||||
pub fn id_of(&self, path: &str) -> FileId {
|
pub fn id_of(&self, path: &str) -> FileId {
|
||||||
let (idx, _) = self.files.iter().enumerate()
|
let (idx, _) = self
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
.find(|(_, (p, _text))| path == p)
|
.find(|(_, (p, _text))| path == p)
|
||||||
.expect("no file in this mock");
|
.expect("no file in this mock");
|
||||||
FileId(idx as u32 + 1)
|
FileId(idx as u32 + 1)
|
||||||
|
|
|
@ -57,10 +57,7 @@ impl SymbolIndex {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
pub(crate) fn search(
|
pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<(FileId, FileSymbol)> {
|
||||||
self,
|
|
||||||
indices: &[Arc<SymbolIndex>],
|
|
||||||
) -> Vec<(FileId, FileSymbol)> {
|
|
||||||
let mut op = fst::map::OpBuilder::new();
|
let mut op = fst::map::OpBuilder::new();
|
||||||
for file_symbols in indices.iter() {
|
for file_symbols in indices.iter() {
|
||||||
let automaton = fst::automaton::Subsequence::new(&self.lowercased);
|
let automaton = fst::automaton::Subsequence::new(&self.lowercased);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
File, TextRange, SyntaxKind, SyntaxNode, SyntaxNodeRef,
|
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
|
File, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::FileId;
|
|
||||||
use crate::db::SyntaxDatabase;
|
use crate::db::SyntaxDatabase;
|
||||||
|
use crate::FileId;
|
||||||
|
|
||||||
salsa::query_group! {
|
salsa::query_group! {
|
||||||
pub(crate) trait SyntaxPtrDatabase: SyntaxDatabase {
|
pub(crate) trait SyntaxPtrDatabase: SyntaxDatabase {
|
||||||
|
@ -52,12 +52,10 @@ trait ToAst {
|
||||||
impl<'a> ToAst for &'a OwnedAst<ast::FnDef<'static>> {
|
impl<'a> ToAst for &'a OwnedAst<ast::FnDef<'static>> {
|
||||||
type Ast = ast::FnDef<'a>;
|
type Ast = ast::FnDef<'a>;
|
||||||
fn to_ast(self) -> ast::FnDef<'a> {
|
fn to_ast(self) -> ast::FnDef<'a> {
|
||||||
ast::FnDef::cast(self.syntax.borrowed())
|
ast::FnDef::cast(self.syntax.borrowed()).unwrap()
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A pionter to a syntax node inside a file.
|
/// A pionter to a syntax node inside a file.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct LocalSyntaxPtr {
|
pub(crate) struct LocalSyntaxPtr {
|
||||||
|
@ -79,22 +77,29 @@ impl LocalSyntaxPtr {
|
||||||
if curr.range() == self.range && curr.kind() == self.kind {
|
if curr.range() == self.range && curr.kind() == self.kind {
|
||||||
return curr.owned();
|
return curr.owned();
|
||||||
}
|
}
|
||||||
curr = curr.children()
|
curr = curr
|
||||||
|
.children()
|
||||||
.find(|it| self.range.is_subrange(&it.range()))
|
.find(|it| self.range.is_subrange(&it.range()))
|
||||||
.unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
|
.unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr {
|
pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr {
|
||||||
SyntaxPtr { file_id, local: self}
|
SyntaxPtr {
|
||||||
|
file_id,
|
||||||
|
local: self,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_local_syntax_ptr() {
|
fn test_local_syntax_ptr() {
|
||||||
let file = File::parse("struct Foo { f: u32, }");
|
let file = File::parse("struct Foo { f: u32, }");
|
||||||
let field = file.syntax().descendants().find_map(ast::NamedFieldDef::cast).unwrap();
|
let field = file
|
||||||
|
.syntax()
|
||||||
|
.descendants()
|
||||||
|
.find_map(ast::NamedFieldDef::cast)
|
||||||
|
.unwrap();
|
||||||
let ptr = LocalSyntaxPtr::new(field.syntax());
|
let ptr = LocalSyntaxPtr::new(field.syntax());
|
||||||
let field_syntax = ptr.resolve(&file);
|
let field_syntax = ptr.resolve(&file);
|
||||||
assert_eq!(field.syntax(), field_syntax);
|
assert_eq!(field.syntax(), field_syntax);
|
||||||
|
|
|
@ -5,42 +5,53 @@ extern crate relative_path;
|
||||||
extern crate rustc_hash;
|
extern crate rustc_hash;
|
||||||
extern crate test_utils;
|
extern crate test_utils;
|
||||||
|
|
||||||
use ra_syntax::{TextRange};
|
use ra_syntax::TextRange;
|
||||||
use test_utils::{assert_eq_dbg};
|
use test_utils::assert_eq_dbg;
|
||||||
|
|
||||||
use ra_analysis::{
|
use ra_analysis::{
|
||||||
|
mock_analysis::{analysis_and_position, single_file, single_file_with_position, MockAnalysis},
|
||||||
AnalysisChange, CrateGraph, FileId, FnDescriptor,
|
AnalysisChange, CrateGraph, FileId, FnDescriptor,
|
||||||
mock_analysis::{MockAnalysis, single_file, single_file_with_position, analysis_and_position},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
|
fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
|
||||||
let (analysis, position) = single_file_with_position(text);
|
let (analysis, position) = single_file_with_position(text);
|
||||||
analysis.resolve_callable(position.file_id, position.offset).unwrap().unwrap()
|
analysis
|
||||||
|
.resolve_callable(position.file_id, position.offset)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resolve_module() {
|
fn test_resolve_module() {
|
||||||
let (analysis, pos) = analysis_and_position("
|
let (analysis, pos) = analysis_and_position(
|
||||||
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod <|>foo;
|
mod <|>foo;
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
// empty
|
// empty
|
||||||
");
|
",
|
||||||
|
);
|
||||||
|
|
||||||
let symbols = analysis.approximately_resolve_symbol(pos.file_id, pos.offset).unwrap();
|
let symbols = analysis
|
||||||
|
.approximately_resolve_symbol(pos.file_id, pos.offset)
|
||||||
|
.unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
|
r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
|
||||||
&symbols,
|
&symbols,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (analysis, pos) = analysis_and_position("
|
let (analysis, pos) = analysis_and_position(
|
||||||
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod <|>foo;
|
mod <|>foo;
|
||||||
//- /foo/mod.rs
|
//- /foo/mod.rs
|
||||||
// empty
|
// empty
|
||||||
");
|
",
|
||||||
|
);
|
||||||
|
|
||||||
let symbols = analysis.approximately_resolve_symbol(pos.file_id, pos.offset).unwrap();
|
let symbols = analysis
|
||||||
|
.approximately_resolve_symbol(pos.file_id, pos.offset)
|
||||||
|
.unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
|
r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
|
||||||
&symbols,
|
&symbols,
|
||||||
|
@ -73,12 +84,14 @@ fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resolve_parent_module() {
|
fn test_resolve_parent_module() {
|
||||||
let (analysis, pos) = analysis_and_position("
|
let (analysis, pos) = analysis_and_position(
|
||||||
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod foo;
|
mod foo;
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
<|>// empty
|
<|>// empty
|
||||||
");
|
",
|
||||||
|
);
|
||||||
let symbols = analysis.parent_module(pos.file_id).unwrap();
|
let symbols = analysis.parent_module(pos.file_id).unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
|
r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
|
||||||
|
@ -88,12 +101,14 @@ fn test_resolve_parent_module() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_resolve_crate_root() {
|
fn test_resolve_crate_root() {
|
||||||
let mock = MockAnalysis::with_files("
|
let mock = MockAnalysis::with_files(
|
||||||
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod foo;
|
mod foo;
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
// emtpy <|>
|
// emtpy <|>
|
||||||
");
|
",
|
||||||
|
);
|
||||||
let root_file = mock.id_of("/lib.rs");
|
let root_file = mock.id_of("/lib.rs");
|
||||||
let mod_file = mock.id_of("/foo.rs");
|
let mod_file = mock.id_of("/foo.rs");
|
||||||
let mut host = mock.analysis_host();
|
let mut host = mock.analysis_host();
|
||||||
|
@ -245,8 +260,10 @@ pub fn do() {
|
||||||
assert_eq!(desc.ret_type, Some("-> i32".to_string()));
|
assert_eq!(desc.ret_type, Some("-> i32".to_string()));
|
||||||
assert_eq!(param, Some(0));
|
assert_eq!(param, Some(0));
|
||||||
assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string());
|
assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string());
|
||||||
assert_eq!(desc.doc, Some(
|
assert_eq!(
|
||||||
r#"Adds one to the number given.
|
desc.doc,
|
||||||
|
Some(
|
||||||
|
r#"Adds one to the number given.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
@ -254,7 +271,10 @@ r#"Adds one to the number given.
|
||||||
let five = 5;
|
let five = 5;
|
||||||
|
|
||||||
assert_eq!(6, my_crate::add_one(5));
|
assert_eq!(6, my_crate::add_one(5));
|
||||||
```"#.into()));
|
```"#
|
||||||
|
.into()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -280,15 +300,18 @@ impl addr {
|
||||||
pub fn do_it() {
|
pub fn do_it() {
|
||||||
addr {};
|
addr {};
|
||||||
addr::add_one(<|>);
|
addr::add_one(<|>);
|
||||||
}"#);
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(desc.name, "add_one".to_string());
|
assert_eq!(desc.name, "add_one".to_string());
|
||||||
assert_eq!(desc.params, vec!["x".to_string()]);
|
assert_eq!(desc.params, vec!["x".to_string()]);
|
||||||
assert_eq!(desc.ret_type, Some("-> i32".to_string()));
|
assert_eq!(desc.ret_type, Some("-> i32".to_string()));
|
||||||
assert_eq!(param, Some(0));
|
assert_eq!(param, Some(0));
|
||||||
assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string());
|
assert_eq!(desc.label, "pub fn add_one(x: i32) -> i32".to_string());
|
||||||
assert_eq!(desc.doc, Some(
|
assert_eq!(
|
||||||
r#"Adds one to the number given.
|
desc.doc,
|
||||||
|
Some(
|
||||||
|
r#"Adds one to the number given.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
|
@ -296,7 +319,10 @@ r#"Adds one to the number given.
|
||||||
let five = 5;
|
let five = 5;
|
||||||
|
|
||||||
assert_eq!(6, my_crate::add_one(5));
|
assert_eq!(6, my_crate::add_one(5));
|
||||||
```"#.into()));
|
```"#
|
||||||
|
.into()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -329,22 +355,32 @@ pub fn foo() {
|
||||||
r.finished(<|>);
|
r.finished(<|>);
|
||||||
}
|
}
|
||||||
|
|
||||||
"#);
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(desc.name, "finished".to_string());
|
assert_eq!(desc.name, "finished".to_string());
|
||||||
assert_eq!(desc.params, vec!["&mut self".to_string(), "ctx".to_string()]);
|
assert_eq!(
|
||||||
|
desc.params,
|
||||||
|
vec!["&mut self".to_string(), "ctx".to_string()]
|
||||||
|
);
|
||||||
assert_eq!(desc.ret_type, None);
|
assert_eq!(desc.ret_type, None);
|
||||||
assert_eq!(param, Some(1));
|
assert_eq!(param, Some(1));
|
||||||
assert_eq!(desc.doc, Some(
|
assert_eq!(
|
||||||
r#"Method is called when writer finishes.
|
desc.doc,
|
||||||
|
Some(
|
||||||
|
r#"Method is called when writer finishes.
|
||||||
|
|
||||||
By default this method stops actor's `Context`."#.into()));
|
By default this method stops actor's `Context`."#
|
||||||
|
.into()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
|
fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
|
||||||
let (analysis, position) = single_file_with_position(text);
|
let (analysis, position) = single_file_with_position(text);
|
||||||
analysis.find_all_refs(position.file_id, position.offset).unwrap()
|
analysis
|
||||||
|
.find_all_refs(position.file_id, position.offset)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -390,14 +426,19 @@ fn test_find_all_refs_for_fn_param() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complete_crate_path() {
|
fn test_complete_crate_path() {
|
||||||
let (analysis, position) = analysis_and_position("
|
let (analysis, position) = analysis_and_position(
|
||||||
|
"
|
||||||
//- /lib.rs
|
//- /lib.rs
|
||||||
mod foo;
|
mod foo;
|
||||||
struct Spam;
|
struct Spam;
|
||||||
//- /foo.rs
|
//- /foo.rs
|
||||||
use crate::Sp<|>
|
use crate::Sp<|>
|
||||||
");
|
",
|
||||||
let completions = analysis.completions(position.file_id, position.offset).unwrap().unwrap();
|
);
|
||||||
|
let completions = analysis
|
||||||
|
.completions(position.file_id, position.offset)
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
assert_eq_dbg(
|
assert_eq_dbg(
|
||||||
r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
|
r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
|
||||||
CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
|
CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
|
||||||
|
|
|
@ -174,8 +174,16 @@ mod tests {
|
||||||
let file = File::parse(&text);
|
let file = File::parse(&text);
|
||||||
let folds = folding_ranges(&file);
|
let folds = folding_ranges(&file);
|
||||||
|
|
||||||
assert_eq!(folds.len(), ranges.len(), "The amount of folds is different than the expected amount");
|
assert_eq!(
|
||||||
assert_eq!(folds.len(), fold_kinds.len(), "The amount of fold kinds is different than the expected amount");
|
folds.len(),
|
||||||
|
ranges.len(),
|
||||||
|
"The amount of folds is different than the expected amount"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
folds.len(),
|
||||||
|
fold_kinds.len(),
|
||||||
|
"The amount of fold kinds is different than the expected amount"
|
||||||
|
);
|
||||||
for ((fold, range), fold_kind) in folds
|
for ((fold, range), fold_kind) in folds
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(ranges.into_iter())
|
.zip(ranges.into_iter())
|
||||||
|
|
|
@ -148,8 +148,6 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
|
||||||
leaf.ancestors().filter_map(N::cast).next()
|
leaf.ancestors().filter_map(N::cast).next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
use crate::TextRange;
|
use crate::TextRange;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
algo::{
|
algo::visit::{visitor, Visitor},
|
||||||
visit::{visitor, Visitor},
|
|
||||||
},
|
|
||||||
ast::{self, NameOwner},
|
ast::{self, NameOwner},
|
||||||
AstNode, File, SmolStr, SyntaxKind, SyntaxNodeRef,
|
AstNode, File, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent,
|
||||||
WalkEvent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -54,7 +51,6 @@ pub fn file_structure(file: &File) -> Vec<StructureNode> {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
|
|
||||||
for event in file.syntax().preorder() {
|
for event in file.syntax().preorder() {
|
||||||
match event {
|
match event {
|
||||||
WalkEvent::Enter(node) => {
|
WalkEvent::Enter(node) => {
|
||||||
|
@ -63,7 +59,7 @@ pub fn file_structure(file: &File) -> Vec<StructureNode> {
|
||||||
stack.push(res.len());
|
stack.push(res.len());
|
||||||
res.push(symbol);
|
res.push(symbol);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
WalkEvent::Leave(node) => {
|
WalkEvent::Leave(node) => {
|
||||||
if structure_node(node).is_some() {
|
if structure_node(node).is_some() {
|
||||||
stack.pop().unwrap();
|
stack.pop().unwrap();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use languageserver_types::{
|
use languageserver_types::{
|
||||||
CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions,
|
CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions,
|
||||||
ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities,
|
ExecuteCommandOptions, FoldingRangeProviderCapability, RenameOptions, RenameProviderCapability,
|
||||||
SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
|
ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
|
||||||
TextDocumentSyncOptions, RenameProviderCapability, RenameOptions
|
TextDocumentSyncOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn server_capabilities() -> ServerCapabilities {
|
pub fn server_capabilities() -> ServerCapabilities {
|
||||||
|
@ -40,8 +40,8 @@ pub fn server_capabilities() -> ServerCapabilities {
|
||||||
more_trigger_character: None,
|
more_trigger_character: None,
|
||||||
}),
|
}),
|
||||||
folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
|
folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
|
||||||
rename_provider: Some(RenameProviderCapability::Options(RenameOptions{
|
rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
|
||||||
prepare_provider: Some(true)
|
prepare_provider: Some(true),
|
||||||
})),
|
})),
|
||||||
color_provider: None,
|
color_provider: None,
|
||||||
execute_command_provider: Some(ExecuteCommandOptions {
|
execute_command_provider: Some(ExecuteCommandOptions {
|
||||||
|
|
|
@ -192,7 +192,8 @@ impl TryConvWith for SourceChange {
|
||||||
.map(|it| it.edits.as_slice())
|
.map(|it| it.edits.as_slice())
|
||||||
.unwrap_or(&[]);
|
.unwrap_or(&[]);
|
||||||
let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
|
let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
|
||||||
let position = Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col)));
|
let position =
|
||||||
|
Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col)));
|
||||||
Some(TextDocumentPositionParams {
|
Some(TextDocumentPositionParams {
|
||||||
text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
|
text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
|
||||||
position,
|
position,
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use gen_lsp_server::ErrorCode;
|
||||||
use languageserver_types::{
|
use languageserver_types::{
|
||||||
CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
|
CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
|
||||||
DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams,
|
DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
|
||||||
InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit,
|
FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position,
|
||||||
RenameParams, WorkspaceEdit, PrepareRenameResponse, Documentation, MarkupContent, MarkupKind
|
PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
|
||||||
|
WorkspaceEdit,
|
||||||
};
|
};
|
||||||
use gen_lsp_server::ErrorCode;
|
|
||||||
use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
|
use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
|
||||||
use ra_syntax::text_utils::contains_offset_nonstrict;
|
use ra_syntax::text_utils::contains_offset_nonstrict;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use serde_json::to_value;
|
use serde_json::to_value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -17,13 +18,10 @@ use crate::{
|
||||||
project_model::TargetKind,
|
project_model::TargetKind,
|
||||||
req::{self, Decoration},
|
req::{self, Decoration},
|
||||||
server_world::ServerWorld,
|
server_world::ServerWorld,
|
||||||
Result, LspError
|
LspError, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn handle_syntax_tree(
|
pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> {
|
||||||
world: ServerWorld,
|
|
||||||
params: req::SyntaxTreeParams,
|
|
||||||
) -> Result<String> {
|
|
||||||
let id = params.text_document.try_conv_with(&world)?;
|
let id = params.text_document.try_conv_with(&world)?;
|
||||||
let res = world.analysis().syntax_tree(id);
|
let res = world.analysis().syntax_tree(id);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
|
@ -182,10 +180,7 @@ pub fn handle_workspace_symbol(
|
||||||
|
|
||||||
return Ok(Some(res));
|
return Ok(Some(res));
|
||||||
|
|
||||||
fn exec_query(
|
fn exec_query(world: &ServerWorld, query: Query) -> Result<Vec<SymbolInformation>> {
|
||||||
world: &ServerWorld,
|
|
||||||
query: Query,
|
|
||||||
) -> Result<Vec<SymbolInformation>> {
|
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for (file_id, symbol) in world.analysis().symbol_search(query)? {
|
for (file_id, symbol) in world.analysis().symbol_search(query)? {
|
||||||
let line_index = world.analysis().file_line_index(file_id);
|
let line_index = world.analysis().file_line_index(file_id);
|
||||||
|
@ -290,7 +285,11 @@ pub fn handle_runnables(
|
||||||
});
|
});
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
|
|
||||||
fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> {
|
fn runnable_args(
|
||||||
|
world: &ServerWorld,
|
||||||
|
file_id: FileId,
|
||||||
|
kind: &RunnableKind,
|
||||||
|
) -> Result<Vec<String>> {
|
||||||
let spec = CargoTargetSpec::for_file(world, file_id)?;
|
let spec = CargoTargetSpec::for_file(world, file_id)?;
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -327,10 +326,7 @@ pub fn handle_runnables(
|
||||||
};
|
};
|
||||||
let file_id = world.analysis().crate_root(crate_id)?;
|
let file_id = world.analysis().crate_root(crate_id)?;
|
||||||
let path = world.path_map.get_path(file_id);
|
let path = world.path_map.get_path(file_id);
|
||||||
let res = world
|
let res = world.workspaces.iter().find_map(|ws| {
|
||||||
.workspaces
|
|
||||||
.iter()
|
|
||||||
.find_map(|ws| {
|
|
||||||
let tgt = ws.target_by_root(path)?;
|
let tgt = ws.target_by_root(path)?;
|
||||||
let res = CargoTargetSpec {
|
let res = CargoTargetSpec {
|
||||||
package: tgt.package(ws).name(ws).to_string(),
|
package: tgt.package(ws).name(ws).to_string(),
|
||||||
|
@ -367,7 +363,6 @@ pub fn handle_runnables(
|
||||||
}
|
}
|
||||||
TargetKind::Other => (),
|
TargetKind::Other => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,9 +448,7 @@ pub fn handle_signature_help(
|
||||||
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);
|
||||||
|
|
||||||
if let Some((descriptor, active_param)) =
|
if let Some((descriptor, active_param)) = world.analysis().resolve_callable(file_id, offset)? {
|
||||||
world.analysis().resolve_callable(file_id, offset)?
|
|
||||||
{
|
|
||||||
let parameters: Vec<ParameterInformation> = descriptor
|
let parameters: Vec<ParameterInformation> = descriptor
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -468,7 +461,7 @@ pub fn handle_signature_help(
|
||||||
let documentation = if let Some(doc) = descriptor.doc {
|
let documentation = if let Some(doc) = descriptor.doc {
|
||||||
Some(Documentation::MarkupContent(MarkupContent {
|
Some(Documentation::MarkupContent(MarkupContent {
|
||||||
kind: MarkupKind::Markdown,
|
kind: MarkupKind::Markdown,
|
||||||
value: doc
|
value: doc,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -511,16 +504,17 @@ pub fn handle_prepare_rename(
|
||||||
Ok(Some(PrepareRenameResponse::Range(loc.range)))
|
Ok(Some(PrepareRenameResponse::Range(loc.range)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_rename(
|
pub fn handle_rename(world: ServerWorld, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
|
||||||
world: ServerWorld,
|
|
||||||
params: RenameParams,
|
|
||||||
) -> Result<Option<WorkspaceEdit>> {
|
|
||||||
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 offset = params.position.conv_with(&line_index);
|
let offset = params.position.conv_with(&line_index);
|
||||||
|
|
||||||
if params.new_name.is_empty() {
|
if params.new_name.is_empty() {
|
||||||
return Err(LspError::new(ErrorCode::InvalidParams as i32, "New Name cannot be empty".into()).into());
|
return Err(LspError::new(
|
||||||
|
ErrorCode::InvalidParams as i32,
|
||||||
|
"New Name cannot be empty".into(),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let refs = world.analysis().find_all_refs(file_id, offset)?;
|
let refs = world.analysis().find_all_refs(file_id, offset)?;
|
||||||
|
@ -531,10 +525,9 @@ pub fn handle_rename(
|
||||||
let mut changes = HashMap::new();
|
let mut changes = HashMap::new();
|
||||||
for r in refs {
|
for r in refs {
|
||||||
if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
|
if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
|
||||||
changes.entry(loc.uri).or_insert(Vec::new()).push(
|
changes.entry(loc.uri).or_insert(Vec::new()).push(TextEdit {
|
||||||
TextEdit {
|
|
||||||
range: loc.range,
|
range: loc.range,
|
||||||
new_text: params.new_name.clone()
|
new_text: params.new_name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,7 +536,7 @@ pub fn handle_rename(
|
||||||
changes: Some(changes),
|
changes: Some(changes),
|
||||||
|
|
||||||
// TODO: return this instead if client/server support it. See #144
|
// TODO: return this instead if client/server support it. See #144
|
||||||
document_changes : None,
|
document_changes: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,9 +550,11 @@ pub fn handle_references(
|
||||||
|
|
||||||
let refs = world.analysis().find_all_refs(file_id, offset)?;
|
let refs = world.analysis().find_all_refs(file_id, offset)?;
|
||||||
|
|
||||||
Ok(Some(refs.into_iter()
|
Ok(Some(
|
||||||
|
refs.into_iter()
|
||||||
.filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
|
.filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
|
||||||
.collect()))
|
.collect(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_code_action(
|
pub fn handle_code_action(
|
||||||
|
|
|
@ -24,7 +24,10 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
#[fail(display = "Language Server request failed with {}. ({})", code, message)]
|
#[fail(
|
||||||
|
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,
|
||||||
|
@ -32,7 +35,7 @@ pub struct LspError {
|
||||||
|
|
||||||
impl LspError {
|
impl LspError {
|
||||||
pub fn new(code: i32, message: String) -> LspError {
|
pub fn new(code: i32, message: String) -> LspError {
|
||||||
LspError {code, message}
|
LspError { code, message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,11 +217,7 @@ fn main_loop_inner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_task(
|
fn on_task(task: Task, msg_sender: &Sender<RawMessage>, pending_requests: &mut FxHashSet<u64>) {
|
||||||
task: Task,
|
|
||||||
msg_sender: &Sender<RawMessage>,
|
|
||||||
pending_requests: &mut FxHashSet<u64>,
|
|
||||||
) {
|
|
||||||
match task {
|
match task {
|
||||||
Task::Respond(response) => {
|
Task::Respond(response) => {
|
||||||
if pending_requests.remove(&response.id) {
|
if pending_requests.remove(&response.id) {
|
||||||
|
@ -373,12 +372,16 @@ impl<'a> PoolDispatcher<'a> {
|
||||||
self.pool.spawn(move || {
|
self.pool.spawn(move || {
|
||||||
let resp = match f(world, params) {
|
let resp = match f(world, params) {
|
||||||
Ok(resp) => RawResponse::ok::<R>(id, &resp),
|
Ok(resp) => RawResponse::ok::<R>(id, &resp),
|
||||||
Err(e) => {
|
Err(e) => match e.downcast::<LspError>() {
|
||||||
match e.downcast::<LspError>() {
|
Ok(lsp_error) => {
|
||||||
Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message),
|
RawResponse::err(id, lsp_error.code, lsp_error.message)
|
||||||
Err(e) => RawResponse::err(id, ErrorCode::InternalError as i32, format!("{}\n{}", e, e.backtrace()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Err(e) => RawResponse::err(
|
||||||
|
id,
|
||||||
|
ErrorCode::InternalError as i32,
|
||||||
|
format!("{}\n{}", e, e.backtrace()),
|
||||||
|
),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let task = Task::Respond(resp);
|
let task = Task::Respond(resp);
|
||||||
sender.send(task);
|
sender.send(task);
|
||||||
|
@ -412,7 +415,7 @@ fn update_file_notifications_on_threadpool(
|
||||||
if !is_canceled(&e) {
|
if !is_canceled(&e) {
|
||||||
error!("failed to compute diagnostics: {:?}", e);
|
error!("failed to compute diagnostics: {:?}", e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let not = RawNotification::new::<req::PublishDiagnostics>(¶ms);
|
let not = RawNotification::new::<req::PublishDiagnostics>(¶ms);
|
||||||
sender.send(Task::Notify(not));
|
sender.send(Task::Notify(not));
|
||||||
|
@ -423,7 +426,7 @@ fn update_file_notifications_on_threadpool(
|
||||||
if !is_canceled(&e) {
|
if !is_canceled(&e) {
|
||||||
error!("failed to compute decorations: {:?}", e);
|
error!("failed to compute decorations: {:?}", e);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let not = RawNotification::new::<req::PublishDecorations>(¶ms);
|
let not = RawNotification::new::<req::PublishDecorations>(¶ms);
|
||||||
sender.send(Task::Notify(not))
|
sender.send(Task::Notify(not))
|
||||||
|
|
|
@ -33,7 +33,8 @@ impl PathMap {
|
||||||
}
|
}
|
||||||
pub fn get_or_insert(&mut self, path: PathBuf, root: Root) -> (bool, FileId) {
|
pub fn get_or_insert(&mut self, path: PathBuf, root: Root) -> (bool, FileId) {
|
||||||
let mut inserted = false;
|
let mut inserted = false;
|
||||||
let file_id = self.path2id
|
let file_id = self
|
||||||
|
.path2id
|
||||||
.get(path.as_path())
|
.get(path.as_path())
|
||||||
.map(|&id| id)
|
.map(|&id| id)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
|
|
|
@ -6,8 +6,8 @@ pub use languageserver_types::{
|
||||||
notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams,
|
notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CompletionParams,
|
||||||
CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
|
CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
|
||||||
DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
|
DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
|
||||||
PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams,
|
PublishDiagnosticsParams, ReferenceParams, SignatureHelp, TextDocumentEdit,
|
||||||
TextEdit, WorkspaceSymbolParams, ReferenceParams,
|
TextDocumentPositionParams, TextEdit, WorkspaceSymbolParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum SyntaxTree {}
|
pub enum SyntaxTree {}
|
||||||
|
|
|
@ -5,7 +5,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use languageserver_types::Url;
|
use languageserver_types::Url;
|
||||||
use ra_analysis::{Analysis, AnalysisHost, AnalysisChange, CrateGraph, FileId, FileResolver, LibraryData};
|
use ra_analysis::{
|
||||||
|
Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FileResolver, LibraryData,
|
||||||
|
};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -65,9 +67,7 @@ impl ServerWorldState {
|
||||||
Some((file_id, text))
|
Some((file_id, text))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.for_each(|(file_id, text)| {
|
.for_each(|(file_id, text)| change.add_file(file_id, text));
|
||||||
change.add_file(file_id, text)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if inserted {
|
if inserted {
|
||||||
change.set_file_resolver(Arc::new(self.path_map.clone()))
|
change.set_file_resolver(Arc::new(self.path_map.clone()))
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
pub mod visit;
|
pub mod visit;
|
||||||
// pub mod walk;
|
// pub mod walk;
|
||||||
|
|
||||||
use crate::{
|
use crate::{text_utils::contains_offset_nonstrict, SyntaxNodeRef, TextRange, TextUnit};
|
||||||
text_utils::{contains_offset_nonstrict},
|
|
||||||
SyntaxNodeRef, TextRange, TextUnit,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
|
pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset {
|
||||||
let range = node.range();
|
let range = node.range();
|
||||||
|
|
|
@ -66,7 +66,9 @@ pub trait AttrsOwner<'a>: AstNode<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DocCommentsOwner<'a>: AstNode<'a> {
|
pub trait DocCommentsOwner<'a>: AstNode<'a> {
|
||||||
fn doc_comments(self) -> AstChildren<'a, Comment<'a>> { children(self) }
|
fn doc_comments(self) -> AstChildren<'a, Comment<'a>> {
|
||||||
|
children(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the textual content of a doc comment block as a single string.
|
/// Returns the textual content of a doc comment block as a single string.
|
||||||
/// That is, strips leading `///` and joins lines
|
/// That is, strips leading `///` and joins lines
|
||||||
|
@ -74,12 +76,15 @@ pub trait DocCommentsOwner<'a>: AstNode<'a> {
|
||||||
self.doc_comments()
|
self.doc_comments()
|
||||||
.map(|comment| {
|
.map(|comment| {
|
||||||
let prefix = comment.prefix();
|
let prefix = comment.prefix();
|
||||||
let trimmed = comment.text().as_str()
|
let trimmed = comment
|
||||||
|
.text()
|
||||||
|
.as_str()
|
||||||
.trim()
|
.trim()
|
||||||
.trim_start_matches(prefix)
|
.trim_start_matches(prefix)
|
||||||
.trim_start();
|
.trim_start();
|
||||||
trimmed.to_owned()
|
trimmed.to_owned()
|
||||||
}).join("\n")
|
})
|
||||||
|
.join("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +255,6 @@ impl<'a> IfExpr<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum PathSegmentKind<'a> {
|
pub enum PathSegmentKind<'a> {
|
||||||
Name(NameRef<'a>),
|
Name(NameRef<'a>),
|
||||||
|
@ -261,7 +265,9 @@ pub enum PathSegmentKind<'a> {
|
||||||
|
|
||||||
impl<'a> PathSegment<'a> {
|
impl<'a> PathSegment<'a> {
|
||||||
pub fn parent_path(self) -> Path<'a> {
|
pub fn parent_path(self) -> Path<'a> {
|
||||||
self.syntax().parent().and_then(Path::cast)
|
self.syntax()
|
||||||
|
.parent()
|
||||||
|
.and_then(Path::cast)
|
||||||
.expect("segments are always nested in paths")
|
.expect("segments are always nested in paths")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,9 @@ pub use crate::{
|
||||||
reparsing::AtomEdit,
|
reparsing::AtomEdit,
|
||||||
rowan::{SmolStr, TextRange, TextUnit},
|
rowan::{SmolStr, TextRange, TextUnit},
|
||||||
syntax_kinds::SyntaxKind,
|
syntax_kinds::SyntaxKind,
|
||||||
yellow::{Direction, OwnedRoot, RefRoot, SyntaxError, SyntaxNode, SyntaxNodeRef, TreeRoot, WalkEvent},
|
yellow::{
|
||||||
|
Direction, OwnedRoot, RefRoot, SyntaxError, SyntaxNode, SyntaxNodeRef, TreeRoot, WalkEvent,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::yellow::GreenNode;
|
use crate::yellow::GreenNode;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::{
|
use crate::{File, SyntaxKind, SyntaxNodeRef, WalkEvent};
|
||||||
File, SyntaxKind, SyntaxNodeRef, WalkEvent
|
|
||||||
};
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
/// Parse a file and create a string representation of the resulting parse tree.
|
/// Parse a file and create a string representation of the resulting parse tree.
|
||||||
|
|
|
@ -89,7 +89,6 @@ pub fn add_cursor(text: &str, offset: TextUnit) -> String {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FixtureEntry {
|
pub struct FixtureEntry {
|
||||||
pub meta: String,
|
pub meta: String,
|
||||||
|
@ -112,17 +111,21 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> {
|
||||||
macro_rules! flush {
|
macro_rules! flush {
|
||||||
() => {
|
() => {
|
||||||
if let Some(meta) = meta {
|
if let Some(meta) = meta {
|
||||||
res.push(FixtureEntry { meta: meta.to_string(), text: buf.clone() });
|
res.push(FixtureEntry {
|
||||||
|
meta: meta.to_string(),
|
||||||
|
text: buf.clone(),
|
||||||
|
});
|
||||||
buf.clear();
|
buf.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let margin = fixture.lines()
|
let margin = fixture
|
||||||
|
.lines()
|
||||||
.filter(|it| it.trim_start().starts_with("//-"))
|
.filter(|it| it.trim_start().starts_with("//-"))
|
||||||
.map(|it| it.len() - it.trim_start().len())
|
.map(|it| it.len() - it.trim_start().len())
|
||||||
.next().expect("empty fixture");
|
.next()
|
||||||
let lines = fixture.lines()
|
.expect("empty fixture");
|
||||||
.filter_map(|line| {
|
let lines = fixture.lines().filter_map(|line| {
|
||||||
if line.len() >= margin {
|
if line.len() >= margin {
|
||||||
assert!(line[..margin].trim().is_empty());
|
assert!(line[..margin].trim().is_empty());
|
||||||
Some(&line[margin..])
|
Some(&line[margin..])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
extern crate itertools;
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate itertools;
|
||||||
extern crate teraron;
|
extern crate teraron;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -7,10 +7,10 @@ use std::{
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
use failure::bail;
|
use failure::bail;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
pub use teraron::{Mode, Verify, Overwrite};
|
pub use teraron::{Mode, Overwrite, Verify};
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
pub type Result<T> = ::std::result::Result<T, failure::Error>;
|
||||||
|
|
||||||
|
@ -63,16 +63,8 @@ pub fn generate(mode: Mode) -> Result<()> {
|
||||||
let grammar = project_root().join(GRAMMAR);
|
let grammar = project_root().join(GRAMMAR);
|
||||||
let syntax_kinds = project_root().join(SYNTAX_KINDS);
|
let syntax_kinds = project_root().join(SYNTAX_KINDS);
|
||||||
let ast = project_root().join(AST);
|
let ast = project_root().join(AST);
|
||||||
teraron::generate(
|
teraron::generate(&syntax_kinds, &grammar, mode)?;
|
||||||
&syntax_kinds,
|
teraron::generate(&ast, &grammar, mode)?;
|
||||||
&grammar,
|
|
||||||
mode,
|
|
||||||
)?;
|
|
||||||
teraron::generate(
|
|
||||||
&ast,
|
|
||||||
&grammar,
|
|
||||||
mode,
|
|
||||||
)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +93,18 @@ pub fn run(cmdline: &str, dir: &str) -> Result<()> {
|
||||||
|
|
||||||
pub fn run_rustfmt(mode: Mode) -> Result<()> {
|
pub fn run_rustfmt(mode: Mode) -> Result<()> {
|
||||||
run(&format!("rustup install {}", TOOLCHAIN), ".")?;
|
run(&format!("rustup install {}", TOOLCHAIN), ".")?;
|
||||||
run(&format!("rustup component add rustfmt-preview --toolchain {}", TOOLCHAIN), ".")?;
|
run(
|
||||||
|
&format!(
|
||||||
|
"rustup component add rustfmt-preview --toolchain {}",
|
||||||
|
TOOLCHAIN
|
||||||
|
),
|
||||||
|
".",
|
||||||
|
)?;
|
||||||
if mode == Verify {
|
if mode == Verify {
|
||||||
run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
|
run(
|
||||||
|
&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN),
|
||||||
|
".",
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
|
run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate teraron;
|
||||||
extern crate tools;
|
extern crate tools;
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
extern crate teraron;
|
|
||||||
|
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
|
use failure::bail;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use tools::{
|
use tools::{collect_tests, generate, run, run_rustfmt, Mode, Overwrite, Result, Test, Verify};
|
||||||
collect_tests, Result, Test, generate, Mode, Overwrite, Verify, run, run_rustfmt,
|
|
||||||
};
|
|
||||||
use failure::bail;
|
|
||||||
|
|
||||||
const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar";
|
const GRAMMAR_DIR: &str = "./crates/ra_syntax/src/grammar";
|
||||||
const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline";
|
const INLINE_TESTS_DIR: &str = "./crates/ra_syntax/tests/data/parser/inline";
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
extern crate tools;
|
extern crate tools;
|
||||||
|
|
||||||
use tools::{
|
use tools::{generate, run_rustfmt, Verify};
|
||||||
generate, Verify, run_rustfmt,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn verify_template_generation() {
|
fn verify_template_generation() {
|
||||||
|
@ -14,6 +12,9 @@ fn verify_template_generation() {
|
||||||
#[test]
|
#[test]
|
||||||
fn check_code_formatting() {
|
fn check_code_formatting() {
|
||||||
if let Err(error) = run_rustfmt(Verify) {
|
if let Err(error) = run_rustfmt(Verify) {
|
||||||
panic!("{}. Please format the code by running `cargo format`", error);
|
panic!(
|
||||||
|
"{}. Please format the code by running `cargo format`",
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue