Reformat all

This commit is contained in:
Aleksey Kladov 2018-10-31 23:41:43 +03:00
parent 857c1650ef
commit 6be50f7d5d
35 changed files with 423 additions and 367 deletions

View file

@ -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::*;

View file

@ -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)]

View file

@ -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`

View file

@ -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
} }
} }

View file

@ -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 = {

View file

@ -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();

View file

@ -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)

View file

@ -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
} }
} }

View file

@ -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);

View file

@ -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()

View file

@ -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};

View file

@ -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,
}
} }
} }

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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 }]"#,

View file

@ -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())

View file

@ -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::*;

View file

@ -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();

View file

@ -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 {

View file

@ -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,

View file

@ -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(

View file

@ -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>(&params); let not = RawNotification::new::<req::PublishDiagnostics>(&params);
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>(&params); let not = RawNotification::new::<req::PublishDecorations>(&params);
sender.send(Task::Notify(not)) sender.send(Task::Notify(not))

View file

@ -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(|| {

View file

@ -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 {}

View file

@ -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()))

View file

@ -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();

View file

@ -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")
} }

View file

@ -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;

View file

@ -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.

View file

@ -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..])

View file

@ -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), ".")?;
} }

View file

@ -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";

View file

@ -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
);
} }
} }