From a409a12f1b3c7aa6c09405bf8e28f73b9761fd18 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 24 Oct 2019 19:19:22 +0300 Subject: [PATCH 001/102] simplify --- xtask/src/codegen/gen_parser_tests.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs index 0f550d94884d..e6eeb29a1eae 100644 --- a/xtask/src/codegen/gen_parser_tests.rs +++ b/xtask/src/codegen/gen_parser_tests.rs @@ -56,16 +56,16 @@ struct Tests { pub err: HashMap, } -fn collect_tests(s: &str) -> Vec<(usize, Test)> { +fn collect_tests(s: &str) -> Vec { let mut res = vec![]; let prefix = "// "; - let lines = s.lines().map(str::trim_start).enumerate(); + let lines = s.lines().map(str::trim_start); let mut block = vec![]; - for (line_idx, line) in lines { + for line in lines { let is_comment = line.starts_with(prefix); if is_comment { - block.push((line_idx, &line[prefix.len()..])); + block.push(&line[prefix.len()..]); } else { process_block(&mut res, &block); block.clear(); @@ -74,29 +74,28 @@ fn collect_tests(s: &str) -> Vec<(usize, Test)> { process_block(&mut res, &block); return res; - fn process_block(acc: &mut Vec<(usize, Test)>, block: &[(usize, &str)]) { + fn process_block(acc: &mut Vec, block: &[&str]) { if block.is_empty() { return; } let mut ok = true; let mut block = block.iter(); - let (start_line, name) = loop { + let name = loop { match block.next() { - Some(&(idx, line)) if line.starts_with("test ") => { - break (idx, line["test ".len()..].to_string()); + Some(line) if line.starts_with("test ") => { + break line["test ".len()..].to_string(); } - Some(&(idx, line)) if line.starts_with("test_err ") => { + Some(line) if line.starts_with("test_err ") => { ok = false; - break (idx, line["test_err ".len()..].to_string()); + break line["test_err ".len()..].to_string(); } Some(_) => (), None => return, } }; - let text: String = - block.map(|(_, line)| *line).chain(std::iter::once("")).collect::>().join("\n"); + let text: String = block.copied().chain(std::iter::once("")).collect::>().join("\n"); assert!(!text.trim().is_empty() && text.ends_with('\n')); - acc.push((start_line, Test { name, text, ok })) + acc.push(Test { name, text, ok }) } } @@ -118,7 +117,7 @@ fn tests_from_dir(dir: &Path) -> Result { fn process_file(res: &mut Tests, path: &Path) -> Result<()> { let text = fs::read_to_string(path)?; - for (_, test) in collect_tests(&text) { + for test in collect_tests(&text) { if test.ok { if let Some(old_test) = res.ok.insert(test.name.clone(), test) { Err(format!("Duplicate test: {}", old_test.name))? From a40d02c9eb1c7226bc7db87b014dc827e77f2a08 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 24 Oct 2019 19:29:38 +0300 Subject: [PATCH 002/102] refactor comment extraction from tasks --- xtask/src/codegen.rs | 25 +++++++++++- xtask/src/codegen/gen_parser_tests.rs | 58 +++++++++------------------ 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index 948b867192b8..bf3a9011950d 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs @@ -8,7 +8,7 @@ mod gen_syntax; mod gen_parser_tests; -use std::{fs, path::Path}; +use std::{fs, mem, path::Path}; use crate::Result; @@ -44,3 +44,26 @@ pub fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { fs::write(path, contents)?; Ok(()) } + +fn extract_comment_blocks(text: &str) -> Vec> { + let mut res = Vec::new(); + + let prefix = "// "; + let lines = text.lines().map(str::trim_start); + + let mut block = vec![]; + for line in lines { + let is_comment = line.starts_with(prefix); + if is_comment { + block.push(line[prefix.len()..].to_string()); + } else { + if !block.is_empty() { + res.push(mem::replace(&mut block, Vec::new())) + } + } + } + if !block.is_empty() { + res.push(mem::replace(&mut block, Vec::new())) + } + res +} diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs index e6eeb29a1eae..db1e59daccc1 100644 --- a/xtask/src/codegen/gen_parser_tests.rs +++ b/xtask/src/codegen/gen_parser_tests.rs @@ -3,12 +3,12 @@ use std::{ collections::HashMap, - fs, + fs, iter, path::{Path, PathBuf}, }; use crate::{ - codegen::{self, update, Mode}, + codegen::{self, extract_comment_blocks, update, Mode}, project_root, Result, }; @@ -57,46 +57,28 @@ struct Tests { } fn collect_tests(s: &str) -> Vec { - let mut res = vec![]; - let prefix = "// "; - let lines = s.lines().map(str::trim_start); - - let mut block = vec![]; - for line in lines { - let is_comment = line.starts_with(prefix); - if is_comment { - block.push(&line[prefix.len()..]); + let mut res = Vec::new(); + for comment_block in extract_comment_blocks(s) { + let first_line = &comment_block[0]; + let (name, ok) = if first_line.starts_with("test ") { + let name = first_line["test ".len()..].to_string(); + (name, true) + } else if first_line.starts_with("test_err ") { + let name = first_line["test_err ".len()..].to_string(); + (name, false) } else { - process_block(&mut res, &block); - block.clear(); - } - } - process_block(&mut res, &block); - return res; - - fn process_block(acc: &mut Vec, block: &[&str]) { - if block.is_empty() { - return; - } - let mut ok = true; - let mut block = block.iter(); - let name = loop { - match block.next() { - Some(line) if line.starts_with("test ") => { - break line["test ".len()..].to_string(); - } - Some(line) if line.starts_with("test_err ") => { - ok = false; - break line["test_err ".len()..].to_string(); - } - Some(_) => (), - None => return, - } + continue; }; - let text: String = block.copied().chain(std::iter::once("")).collect::>().join("\n"); + let text: String = comment_block[1..] + .iter() + .cloned() + .chain(iter::once(String::new())) + .collect::>() + .join("\n"); assert!(!text.trim().is_empty() && text.ends_with('\n')); - acc.push(Test { name, text, ok }) + res.push(Test { name, text, ok }) } + res } fn tests_from_dir(dir: &Path) -> Result { From f28801b094d62824ab2cce4b4bc97611f274aacd Mon Sep 17 00:00:00 2001 From: memoryruins Date: Thu, 24 Oct 2019 17:01:42 -0400 Subject: [PATCH 003/102] Update rustdoc link pt.2 --- docs/dev/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index e5a7ea5f6f07..006518afc0ff 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -14,7 +14,7 @@ To learn more about how rust-analyzer works, see We also publish rustdoc docs to pages: -https://rust-analyzer.github.io/rust-analyzer/api-docs/ra_ide_api/ +https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/ Various organizational and process issues are discussed in this document. From dc65219ae1216e747215fe937b248ebf2469f33f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 09:00:30 +0300 Subject: [PATCH 004/102] document feature flags --- crates/ra_lsp_server/src/config.rs | 14 +++++++++----- docs/user/README.md | 13 +++++++++++-- editors/code/package.json | 5 ----- editors/code/src/config.ts | 7 ------- editors/code/src/server.ts | 2 -- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs index 579d4c6926b5..9871a3b37f39 100644 --- a/crates/ra_lsp_server/src/config.rs +++ b/crates/ra_lsp_server/src/config.rs @@ -1,4 +1,11 @@ -//! FIXME: write short doc here +//! Config used by the language server. +//! +//! We currently get this config from `initialize` LSP request, which is not the +//! best way to do it, but was the simplest thing we could implement. +//! +//! Of particular interest is the `feature_flags` hash map: while other fields +//! configure the server itself, feature flags are passed into analysis, and +//! tweak things like automatic insertion of `()` in completions. use rustc_hash::FxHashMap; @@ -72,10 +79,7 @@ mod test { assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); assert_eq!( default, - serde_json::from_str( - r#"{"publishDecorations":null, "showWorkspaceLoaded":null, "lruCapacity":null}"# - ) - .unwrap() + serde_json::from_str(r#"{"publishDecorations":null, "lruCapacity":null}"#).unwrap() ); } } diff --git a/docs/user/README.md b/docs/user/README.md index f1628d6a424c..a1cef22cc6a3 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -83,8 +83,6 @@ host. ### Settings * `rust-analyzer.highlightingOn`: enables experimental syntax highlighting -* `rust-analyzer.showWorkspaceLoadedNotification`: to ease troubleshooting, a - notification is shown by default when a workspace is loaded * `rust-analyzer.enableEnhancedTyping`: by default, rust-analyzer intercepts `Enter` key to make it easier to continue comments. Note that it may conflict with VIM emulation plugin. * `rust-analyzer.raLspServerPath`: path to `ra_lsp_server` executable @@ -102,6 +100,17 @@ host. * `rust-analyzer.trace.server`: enables internal logging * `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging * `RUST_SRC_PATH`: environment variable that overwrites the sysroot +* `rust-analyzer.featureFlags` -- a JSON object to tweak fine-grained behavior: + ```js + { + // Show diagnostics produced by rust-analyzer itself. + "lsp.diagnostics": true, + // Automatically insert `()` and `<>` when completing functions and types. + "completion.insertion.add-call-parenthesis": true, + // Show notification when workspace is fully loaded + "notifications.workspace-loaded": true, + } + ``` ## Emacs diff --git a/editors/code/package.json b/editors/code/package.json index 4b719aadaf26..ee997e58f5d0 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -229,11 +229,6 @@ "description": "A list of patterns for cargo-watch to ignore (will be passed as `--ignore`)", "default": [] }, - "rust-analyzer.showWorkspaceLoadedNotification": { - "type": "boolean", - "description": "Controls whether rust-analyzer displays a notification when a project is loaded.", - "default": false - }, "rust-analyzer.trace.server": { "type": "string", "scope": "window", diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 331936b5ece8..95c3f42e50ff 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -20,7 +20,6 @@ export class Config { public rainbowHighlightingOn = false; public enableEnhancedTyping = true; public raLspServerPath = RA_LSP_DEBUG || 'ra_lsp_server'; - public showWorkspaceLoadedNotification = true; public lruCapacity: null | number = null; public displayInlayHints = true; public maxInlayHintLength: null | number = null; @@ -56,12 +55,6 @@ export class Config { ) as boolean; } - if (config.has('showWorkspaceLoadedNotification')) { - this.showWorkspaceLoadedNotification = config.get( - 'showWorkspaceLoadedNotification' - ) as boolean; - } - if (!this.highlightingOn && Server) { Server.highlighter.removeHighlights(); } diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts index ff50fcd994cf..a3ef21a16719 100644 --- a/editors/code/src/server.ts +++ b/editors/code/src/server.ts @@ -42,8 +42,6 @@ export class Server { documentSelector: [{ scheme: 'file', language: 'rust' }], initializationOptions: { publishDecorations: true, - showWorkspaceLoaded: - Server.config.showWorkspaceLoadedNotification, lruCapacity: Server.config.lruCapacity, excludeGlobs: Server.config.excludeGlobs, useClientWatching: Server.config.useClientWatching, From 8d2fd59cfb00211573419b0a59cf91d92d636f5a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 11:19:26 +0300 Subject: [PATCH 005/102] make typing infra slightly more extensible --- crates/ra_ide_api/src/lib.rs | 28 ++---- crates/ra_ide_api/src/typing.rs | 92 +++++++++++++------ .../ra_lsp_server/src/main_loop/handlers.rs | 8 +- 3 files changed, 74 insertions(+), 54 deletions(-) diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 0832229fd17c..b2a1d185b6c7 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -407,24 +407,16 @@ impl Analysis { self.with_db(|db| typing::on_enter(&db, position)) } - /// Returns an edit which should be applied after `=` was typed. Primarily, - /// this works when adding `let =`. - // FIXME: use a snippet completion instead of this hack here. - pub fn on_eq_typed(&self, position: FilePosition) -> Cancelable> { - self.with_db(|db| { - let parse = db.parse(position.file_id); - let file = parse.tree(); - let edit = typing::on_eq_typed(&file, position.offset)?; - Some(SourceChange::source_file_edit( - "add semicolon", - SourceFileEdit { edit, file_id: position.file_id }, - )) - }) - } - - /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. - pub fn on_dot_typed(&self, position: FilePosition) -> Cancelable> { - self.with_db(|db| typing::on_dot_typed(&db, position)) + /// Returns an edit which should be applied after a character was typed. + /// + /// This is useful for some on-the-fly fixups, like adding `;` to `let =` + /// automatically. + pub fn on_char_typed( + &self, + position: FilePosition, + char_typed: char, + ) -> Cancelable> { + self.with_db(|db| typing::on_char_typed(&db, position, char_typed)) } /// Returns a tree representation of symbols in the file. Useful to draw a diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 2f5782012be8..44cc461471bf 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -1,4 +1,17 @@ -//! FIXME: write short doc here +//! This module handles auto-magic editing actions applied together with users +//! edits. For example, if the user typed +//! +//! ```text +//! foo +//! .bar() +//! .baz() +//! | // <- cursor is here +//! ``` +//! +//! and types `.` next, we want to indent the dot. +//! +//! Language server executes such typing assists synchronously. That is, they +//! block user's typing and should be pretty fast for this reason! use ra_db::{FilePosition, SourceDatabase}; use ra_fmt::leading_indent; @@ -68,18 +81,50 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option { Some(text[pos..].into()) } -pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option { - assert_eq!(file.syntax().text().char_at(eq_offset), Some('=')); - let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), eq_offset)?; +pub(crate) fn on_char_typed( + db: &RootDatabase, + position: FilePosition, + char_typed: char, +) -> Option { + let file = &db.parse(position.file_id).tree(); + assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); + match char_typed { + '=' => { + let edit = on_eq_typed(file, position.offset)?; + Some(SourceChange::source_file_edit( + "add semicolon", + SourceFileEdit { edit, file_id: position.file_id }, + )) + } + '.' => { + let (edit, cursor_offset) = on_dot_typed(file, position.offset)?; + Some( + SourceChange::source_file_edit( + "reindent dot", + SourceFileEdit { edit, file_id: position.file_id }, + ) + .with_cursor(FilePosition { file_id: position.file_id, offset: cursor_offset }), + ) + } + _ => None, + } +} + +/// Returns an edit which should be applied after `=` was typed. Primarily, +/// this works when adding `let =`. +// FIXME: use a snippet completion instead of this hack here. +fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option { + assert_eq!(file.syntax().text().char_at(offset), Some('=')); + let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; if let_stmt.has_semi() { return None; } if let Some(expr) = let_stmt.initializer() { let expr_range = expr.syntax().text_range(); - if expr_range.contains(eq_offset) && eq_offset != expr_range.start() { + if expr_range.contains(offset) && offset != expr_range.start() { return None; } - if file.syntax().text().slice(eq_offset..expr_range.start()).contains_char('\n') { + if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') { return None; } } else { @@ -91,16 +136,11 @@ pub fn on_eq_typed(file: &SourceFile, eq_offset: TextUnit) -> Option { Some(edit.finish()) } -pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option { - let parse = db.parse(position.file_id); - assert_eq!(parse.tree().syntax().text().char_at(position.offset), Some('.')); - - let whitespace = parse - .tree() - .syntax() - .token_at_offset(position.offset) - .left_biased() - .and_then(ast::Whitespace::cast)?; +/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. +fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<(TextEdit, TextUnit)> { + assert_eq!(file.syntax().text().char_at(offset), Some('.')); + let whitespace = + file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; let current_indent = { let text = whitespace.text(); @@ -118,19 +158,11 @@ pub(crate) fn on_dot_typed(db: &RootDatabase, position: FilePosition) -> Option< return None; } let mut edit = TextEditBuilder::default(); - edit.replace( - TextRange::from_to(position.offset - current_indent_len, position.offset), - target_indent, - ); + edit.replace(TextRange::from_to(offset - current_indent_len, offset), target_indent); - let res = SourceChange::source_file_edit_from("reindent dot", position.file_id, edit.finish()) - .with_cursor(FilePosition { - offset: position.offset + target_indent_len - current_indent_len - + TextUnit::of_char('.'), - file_id: position.file_id, - }); + let cursor_offset = offset + target_indent_len - current_indent_len + TextUnit::of_char('.'); - Some(res) + Some((edit.finish(), cursor_offset)) } #[cfg(test)] @@ -197,9 +229,9 @@ fn foo() { edit.insert(offset, ".".to_string()); let before = edit.finish().apply(&before); let (analysis, file_id) = single_file(&before); - if let Some(result) = analysis.on_dot_typed(FilePosition { offset, file_id }).unwrap() { - assert_eq!(result.source_file_edits.len(), 1); - let actual = result.source_file_edits[0].edit.apply(&before); + let file = analysis.parse(file_id).unwrap(); + if let Some((edit, _cursor_offset)) = on_dot_typed(&file, offset) { + let actual = edit.apply(&before); assert_eq_text!(after, &actual); } else { assert_eq_text!(&before, after) diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index a29971d107aa..530c4d8b6086 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -144,12 +144,8 @@ pub fn handle_on_type_formatting( // in `ra_ide_api`, the `on_type` invariant is that // `text.char_at(position) == typed_char`. position.offset = position.offset - TextUnit::of_char('.'); - - let edit = match params.ch.as_str() { - "=" => world.analysis().on_eq_typed(position), - "." => world.analysis().on_dot_typed(position), - _ => return Ok(None), - }?; + let char_typed = params.ch.chars().next().unwrap_or('\0'); + let edit = world.analysis().on_char_typed(position, char_typed)?; let mut edit = match edit { Some(it) => it, None => return Ok(None), From b112430ca73f646b6cb779ab09a3f691aad22442 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 11:26:53 +0300 Subject: [PATCH 006/102] move source change to a dedicated file --- crates/ra_ide_api/src/lib.rs | 97 +---------------------- crates/ra_ide_api/src/source_change.rs | 102 +++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 95 deletions(-) create mode 100644 crates/ra_ide_api/src/source_change.rs diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index b2a1d185b6c7..6b8aa7a8ea50 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -14,6 +14,7 @@ mod db; pub mod mock_analysis; mod symbol_index; mod change; +mod source_change; mod feature_flags; mod status; @@ -54,8 +55,6 @@ use ra_db::{ CheckCanceled, FileLoader, SourceDatabase, }; use ra_syntax::{SourceFile, TextRange, TextUnit}; -use ra_text_edit::TextEdit; -use relative_path::RelativePathBuf; use crate::{db::LineIndexDatabase, symbol_index::FileSymbol}; @@ -73,6 +72,7 @@ pub use crate::{ line_index_utils::translate_offset_with_edit, references::{ReferenceSearchResult, SearchScope}, runnables::{Runnable, RunnableKind}, + source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, syntax_highlighting::HighlightedRange, }; @@ -83,99 +83,6 @@ pub use ra_db::{ pub type Cancelable = Result; -#[derive(Debug)] -pub struct SourceChange { - pub label: String, - pub source_file_edits: Vec, - pub file_system_edits: Vec, - pub cursor_position: Option, -} - -impl SourceChange { - /// Creates a new SourceChange with the given label - /// from the edits. - pub(crate) fn from_edits>( - label: L, - source_file_edits: Vec, - file_system_edits: Vec, - ) -> Self { - SourceChange { - label: label.into(), - source_file_edits, - file_system_edits, - cursor_position: None, - } - } - - /// Creates a new SourceChange with the given label, - /// containing only the given `SourceFileEdits`. - pub(crate) fn source_file_edits>(label: L, edits: Vec) -> Self { - SourceChange { - label: label.into(), - source_file_edits: edits, - file_system_edits: vec![], - cursor_position: None, - } - } - - /// Creates a new SourceChange with the given label, - /// containing only the given `FileSystemEdits`. - pub(crate) fn file_system_edits>(label: L, edits: Vec) -> Self { - SourceChange { - label: label.into(), - source_file_edits: vec![], - file_system_edits: edits, - cursor_position: None, - } - } - - /// Creates a new SourceChange with the given label, - /// containing only a single `SourceFileEdit`. - pub(crate) fn source_file_edit>(label: L, edit: SourceFileEdit) -> Self { - SourceChange::source_file_edits(label, vec![edit]) - } - - /// Creates a new SourceChange with the given label - /// from the given `FileId` and `TextEdit` - pub(crate) fn source_file_edit_from>( - label: L, - file_id: FileId, - edit: TextEdit, - ) -> Self { - SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit }) - } - - /// Creates a new SourceChange with the given label - /// from the given `FileId` and `TextEdit` - pub(crate) fn file_system_edit>(label: L, edit: FileSystemEdit) -> Self { - SourceChange::file_system_edits(label, vec![edit]) - } - - /// Sets the cursor position to the given `FilePosition` - pub(crate) fn with_cursor(mut self, cursor_position: FilePosition) -> Self { - self.cursor_position = Some(cursor_position); - self - } - - /// Sets the cursor position to the given `FilePosition` - pub(crate) fn with_cursor_opt(mut self, cursor_position: Option) -> Self { - self.cursor_position = cursor_position; - self - } -} - -#[derive(Debug)] -pub struct SourceFileEdit { - pub file_id: FileId, - pub edit: TextEdit, -} - -#[derive(Debug)] -pub enum FileSystemEdit { - CreateFile { source_root: SourceRootId, path: RelativePathBuf }, - MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, -} - #[derive(Debug)] pub struct Diagnostic { pub message: String, diff --git a/crates/ra_ide_api/src/source_change.rs b/crates/ra_ide_api/src/source_change.rs new file mode 100644 index 000000000000..80e8821b0c9c --- /dev/null +++ b/crates/ra_ide_api/src/source_change.rs @@ -0,0 +1,102 @@ +//! This modules defines type to represent changes to the source code, that flow +//! from the server to the client. +//! +//! It can be viewed as a dual for `AnalysisChange`. + +use ra_text_edit::TextEdit; +use relative_path::RelativePathBuf; + +use crate::{FileId, FilePosition, SourceRootId}; + +#[derive(Debug)] +pub struct SourceChange { + pub label: String, + pub source_file_edits: Vec, + pub file_system_edits: Vec, + pub cursor_position: Option, +} + +impl SourceChange { + /// Creates a new SourceChange with the given label + /// from the edits. + pub(crate) fn from_edits>( + label: L, + source_file_edits: Vec, + file_system_edits: Vec, + ) -> Self { + SourceChange { + label: label.into(), + source_file_edits, + file_system_edits, + cursor_position: None, + } + } + + /// Creates a new SourceChange with the given label, + /// containing only the given `SourceFileEdits`. + pub(crate) fn source_file_edits>(label: L, edits: Vec) -> Self { + SourceChange { + label: label.into(), + source_file_edits: edits, + file_system_edits: vec![], + cursor_position: None, + } + } + + /// Creates a new SourceChange with the given label, + /// containing only the given `FileSystemEdits`. + pub(crate) fn file_system_edits>(label: L, edits: Vec) -> Self { + SourceChange { + label: label.into(), + source_file_edits: vec![], + file_system_edits: edits, + cursor_position: None, + } + } + + /// Creates a new SourceChange with the given label, + /// containing only a single `SourceFileEdit`. + pub(crate) fn source_file_edit>(label: L, edit: SourceFileEdit) -> Self { + SourceChange::source_file_edits(label, vec![edit]) + } + + /// Creates a new SourceChange with the given label + /// from the given `FileId` and `TextEdit` + pub(crate) fn source_file_edit_from>( + label: L, + file_id: FileId, + edit: TextEdit, + ) -> Self { + SourceChange::source_file_edit(label, SourceFileEdit { file_id, edit }) + } + + /// Creates a new SourceChange with the given label + /// from the given `FileId` and `TextEdit` + pub(crate) fn file_system_edit>(label: L, edit: FileSystemEdit) -> Self { + SourceChange::file_system_edits(label, vec![edit]) + } + + /// Sets the cursor position to the given `FilePosition` + pub(crate) fn with_cursor(mut self, cursor_position: FilePosition) -> Self { + self.cursor_position = Some(cursor_position); + self + } + + /// Sets the cursor position to the given `FilePosition` + pub(crate) fn with_cursor_opt(mut self, cursor_position: Option) -> Self { + self.cursor_position = cursor_position; + self + } +} + +#[derive(Debug)] +pub struct SourceFileEdit { + pub file_id: FileId, + pub edit: TextEdit, +} + +#[derive(Debug)] +pub enum FileSystemEdit { + CreateFile { source_root: SourceRootId, path: RelativePathBuf }, + MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, +} From 6f00bb1cb0e5fb72fac092d63c07f8652091d4d9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 11:49:38 +0300 Subject: [PATCH 007/102] introduce SingleFileChange --- crates/ra_ide_api/src/source_change.rs | 19 +++++++- crates/ra_ide_api/src/typing.rs | 62 ++++++++++++-------------- crates/ra_text_edit/src/text_edit.rs | 18 ++++++++ 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/crates/ra_ide_api/src/source_change.rs b/crates/ra_ide_api/src/source_change.rs index 80e8821b0c9c..4e63bbf6f0c8 100644 --- a/crates/ra_ide_api/src/source_change.rs +++ b/crates/ra_ide_api/src/source_change.rs @@ -6,7 +6,7 @@ use ra_text_edit::TextEdit; use relative_path::RelativePathBuf; -use crate::{FileId, FilePosition, SourceRootId}; +use crate::{FileId, FilePosition, SourceRootId, TextUnit}; #[derive(Debug)] pub struct SourceChange { @@ -100,3 +100,20 @@ pub enum FileSystemEdit { CreateFile { source_root: SourceRootId, path: RelativePathBuf }, MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, } + +pub(crate) struct SingleFileChange { + pub label: String, + pub edit: TextEdit, + pub cursor_position: Option, +} + +impl SingleFileChange { + pub(crate) fn into_source_change(self, file_id: FileId) -> SourceChange { + SourceChange { + label: self.label, + source_file_edits: vec![SourceFileEdit { file_id, edit: self.edit }], + file_system_edits: Vec::new(), + cursor_position: self.cursor_position.map(|offset| FilePosition { file_id, offset }), + } + } +} diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 44cc461471bf..c5ec6c1c184f 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -24,7 +24,7 @@ use ra_syntax::{ }; use ra_text_edit::{TextEdit, TextEditBuilder}; -use crate::{db::RootDatabase, SourceChange, SourceFileEdit}; +use crate::{db::RootDatabase, source_change::SingleFileChange, SourceChange, SourceFileEdit}; pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option { let parse = db.parse(position.file_id); @@ -88,32 +88,19 @@ pub(crate) fn on_char_typed( ) -> Option { let file = &db.parse(position.file_id).tree(); assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); - match char_typed { - '=' => { - let edit = on_eq_typed(file, position.offset)?; - Some(SourceChange::source_file_edit( - "add semicolon", - SourceFileEdit { edit, file_id: position.file_id }, - )) - } - '.' => { - let (edit, cursor_offset) = on_dot_typed(file, position.offset)?; - Some( - SourceChange::source_file_edit( - "reindent dot", - SourceFileEdit { edit, file_id: position.file_id }, - ) - .with_cursor(FilePosition { file_id: position.file_id, offset: cursor_offset }), - ) - } - _ => None, - } + let single_file_change = match char_typed { + '=' => on_eq_typed(file, position.offset)?, + '.' => on_dot_typed(file, position.offset)?, + _ => return None, + }; + + Some(single_file_change.into_source_change(position.file_id)) } /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. -fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option { +fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option { assert_eq!(file.syntax().text().char_at(offset), Some('=')); let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; if let_stmt.has_semi() { @@ -131,13 +118,15 @@ fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option { return None; } let offset = let_stmt.syntax().text_range().end(); - let mut edit = TextEditBuilder::default(); - edit.insert(offset, ";".to_string()); - Some(edit.finish()) + Some(SingleFileChange { + label: "add semicolon".to_string(), + edit: TextEdit::insert(offset, ";".to_string()), + cursor_position: None, + }) } /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. -fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<(TextEdit, TextUnit)> { +fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option { assert_eq!(file.syntax().text().char_at(offset), Some('.')); let whitespace = file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; @@ -157,12 +146,17 @@ fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option<(TextEdit, TextUn if current_indent_len == target_indent_len { return None; } - let mut edit = TextEditBuilder::default(); - edit.replace(TextRange::from_to(offset - current_indent_len, offset), target_indent); - let cursor_offset = offset + target_indent_len - current_indent_len + TextUnit::of_char('.'); - - Some((edit.finish(), cursor_offset)) + Some(SingleFileChange { + label: "reindent dot".to_string(), + edit: TextEdit::replace( + TextRange::from_to(offset - current_indent_len, offset), + target_indent, + ), + cursor_position: Some( + offset + target_indent_len - current_indent_len + TextUnit::of_char('.'), + ), + }) } #[cfg(test)] @@ -182,7 +176,7 @@ mod tests { let before = edit.finish().apply(&before); let parse = SourceFile::parse(&before); if let Some(result) = on_eq_typed(&parse.tree(), offset) { - let actual = result.apply(&before); + let actual = result.edit.apply(&before); assert_eq_text!(after, &actual); } else { assert_eq_text!(&before, after) @@ -230,8 +224,8 @@ fn foo() { let before = edit.finish().apply(&before); let (analysis, file_id) = single_file(&before); let file = analysis.parse(file_id).unwrap(); - if let Some((edit, _cursor_offset)) = on_dot_typed(&file, offset) { - let actual = edit.apply(&before); + if let Some(result) = on_dot_typed(&file, offset) { + let actual = result.edit.apply(&before); assert_eq_text!(after, &actual); } else { assert_eq_text!(&before, after) diff --git a/crates/ra_text_edit/src/text_edit.rs b/crates/ra_text_edit/src/text_edit.rs index 0381ea000821..413c7d782eb5 100644 --- a/crates/ra_text_edit/src/text_edit.rs +++ b/crates/ra_text_edit/src/text_edit.rs @@ -32,6 +32,24 @@ impl TextEditBuilder { } impl TextEdit { + pub fn insert(offset: TextUnit, text: String) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.insert(offset, text); + builder.finish() + } + + pub fn delete(range: TextRange) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.delete(range); + builder.finish() + } + + pub fn replace(range: TextRange, replace_with: String) -> TextEdit { + let mut builder = TextEditBuilder::default(); + builder.replace(range, replace_with); + builder.finish() + } + pub(crate) fn from_atoms(mut atoms: Vec) -> TextEdit { atoms.sort_by_key(|a| (a.delete.start(), a.delete.end())); for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { From ea948e9fbb519ab5f4a21e0cce0dc5f0f365a716 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 12:04:17 +0300 Subject: [PATCH 008/102] refactor typing_handlers --- crates/ra_ide_api/src/lib.rs | 4 ++ crates/ra_ide_api/src/typing.rs | 72 +++++++++++++++++---------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 6b8aa7a8ea50..d0188da4493e 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -323,6 +323,10 @@ impl Analysis { position: FilePosition, char_typed: char, ) -> Cancelable> { + // Fast path to not even parse the file. + if !typing::TRIGGER_CHARS.contains(char_typed) { + return Ok(None); + } self.with_db(|db| typing::on_char_typed(&db, position, char_typed)) } diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index c5ec6c1c184f..17d0f08a5a09 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -81,22 +81,32 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option { Some(text[pos..].into()) } +pub(crate) const TRIGGER_CHARS: &str = ".="; + pub(crate) fn on_char_typed( db: &RootDatabase, position: FilePosition, char_typed: char, ) -> Option { + assert!(TRIGGER_CHARS.contains(char_typed)); let file = &db.parse(position.file_id).tree(); assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); - let single_file_change = match char_typed { - '=' => on_eq_typed(file, position.offset)?, - '.' => on_dot_typed(file, position.offset)?, - _ => return None, - }; - + let single_file_change = on_char_typed_inner(file, position.offset, char_typed)?; Some(single_file_change.into_source_change(position.file_id)) } +fn on_char_typed_inner( + file: &SourceFile, + offset: TextUnit, + char_typed: char, +) -> Option { + match char_typed { + '.' => on_dot_typed(file, offset), + '=' => on_eq_typed(file, offset), + _ => None, + } +} + /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. @@ -167,22 +177,29 @@ mod tests { use super::*; + fn type_char(char_typed: char, before: &str, after: &str) { + let (offset, before) = extract_offset(before); + let edit = TextEdit::insert(offset, char_typed.to_string()); + let before = edit.apply(&before); + let parse = SourceFile::parse(&before); + if let Some(result) = on_char_typed_inner(&parse.tree(), offset, char_typed) { + let actual = result.edit.apply(&before); + assert_eq_text!(after, &actual); + } else { + assert_eq_text!(&before, after) + }; + } + + fn type_eq(before: &str, after: &str) { + type_char('=', before, after); + } + + fn type_dot(before: &str, after: &str) { + type_char('.', before, after); + } + #[test] fn test_on_eq_typed() { - fn type_eq(before: &str, after: &str) { - let (offset, before) = extract_offset(before); - let mut edit = TextEditBuilder::default(); - edit.insert(offset, "=".to_string()); - let before = edit.finish().apply(&before); - let parse = SourceFile::parse(&before); - if let Some(result) = on_eq_typed(&parse.tree(), offset) { - let actual = result.edit.apply(&before); - assert_eq_text!(after, &actual); - } else { - assert_eq_text!(&before, after) - }; - } - // do_check(r" // fn foo() { // let foo =<|> @@ -217,21 +234,6 @@ fn foo() { // "); } - fn type_dot(before: &str, after: &str) { - let (offset, before) = extract_offset(before); - let mut edit = TextEditBuilder::default(); - edit.insert(offset, ".".to_string()); - let before = edit.finish().apply(&before); - let (analysis, file_id) = single_file(&before); - let file = analysis.parse(file_id).unwrap(); - if let Some(result) = on_dot_typed(&file, offset) { - let actual = result.edit.apply(&before); - assert_eq_text!(after, &actual); - } else { - assert_eq_text!(&before, after) - }; - } - #[test] fn indents_new_chain_call() { type_dot( From 53e3bee0cfcd7541b5ee882ab4b47c9dde9780b8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 12:16:56 +0300 Subject: [PATCH 009/102] insert space after `->` --- crates/ra_ide_api/src/typing.rs | 460 +++++++++--------- crates/ra_lsp_server/src/caps.rs | 2 +- .../ra_lsp_server/src/main_loop/handlers.rs | 1 + 3 files changed, 235 insertions(+), 228 deletions(-) diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 17d0f08a5a09..26a3111fd80d 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -81,7 +81,7 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option { Some(text[pos..].into()) } -pub(crate) const TRIGGER_CHARS: &str = ".="; +pub(crate) const TRIGGER_CHARS: &str = ".=>"; pub(crate) fn on_char_typed( db: &RootDatabase, @@ -100,10 +100,12 @@ fn on_char_typed_inner( offset: TextUnit, char_typed: char, ) -> Option { + assert!(TRIGGER_CHARS.contains(char_typed)); match char_typed { '.' => on_dot_typed(file, offset), '=' => on_eq_typed(file, offset), - _ => None, + '>' => on_arrow_typed(file, offset), + _ => unreachable!(), } } @@ -169,6 +171,25 @@ fn on_dot_typed(file: &SourceFile, offset: TextUnit) -> Option }) } +/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` +fn on_arrow_typed(file: &SourceFile, offset: TextUnit) -> Option { + let file_text = file.syntax().text(); + assert_eq!(file_text.char_at(offset), Some('>')); + let after_arrow = offset + TextUnit::of_char('>'); + if file_text.char_at(after_arrow) != Some('{') { + return None; + } + if find_node_at_offset::(file.syntax(), offset).is_none() { + return None; + } + + Some(SingleFileChange { + label: "add space after return type".to_string(), + edit: TextEdit::insert(after_arrow, " ".to_string()), + cursor_position: Some(after_arrow), + }) +} + #[cfg(test)] mod tests { use test_utils::{add_cursor, assert_eq_text, extract_offset}; @@ -177,231 +198,6 @@ mod tests { use super::*; - fn type_char(char_typed: char, before: &str, after: &str) { - let (offset, before) = extract_offset(before); - let edit = TextEdit::insert(offset, char_typed.to_string()); - let before = edit.apply(&before); - let parse = SourceFile::parse(&before); - if let Some(result) = on_char_typed_inner(&parse.tree(), offset, char_typed) { - let actual = result.edit.apply(&before); - assert_eq_text!(after, &actual); - } else { - assert_eq_text!(&before, after) - }; - } - - fn type_eq(before: &str, after: &str) { - type_char('=', before, after); - } - - fn type_dot(before: &str, after: &str) { - type_char('.', before, after); - } - - #[test] - fn test_on_eq_typed() { - // do_check(r" - // fn foo() { - // let foo =<|> - // } - // ", r" - // fn foo() { - // let foo =; - // } - // "); - type_eq( - r" -fn foo() { - let foo <|> 1 + 1 -} -", - r" -fn foo() { - let foo = 1 + 1; -} -", - ); - // do_check(r" - // fn foo() { - // let foo =<|> - // let bar = 1; - // } - // ", r" - // fn foo() { - // let foo =; - // let bar = 1; - // } - // "); - } - - #[test] - fn indents_new_chain_call() { - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - . - } - ", - ); - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - . - } - ", - ) - } - - #[test] - fn indents_new_chain_call_with_semi() { - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - <|>; - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .; - } - ", - ); - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - <|>; - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .; - } - ", - ) - } - - #[test] - fn indents_continued_chain_call() { - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .first() - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .first() - . - } - ", - ); - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .first() - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - self.child_impl(db, name) - .first() - . - } - ", - ); - } - - #[test] - fn indents_middle_of_chain_call() { - type_dot( - r" - fn source_impl() { - let var = enum_defvariant_list().unwrap() - <|> - .nth(92) - .unwrap(); - } - ", - r" - fn source_impl() { - let var = enum_defvariant_list().unwrap() - . - .nth(92) - .unwrap(); - } - ", - ); - type_dot( - r" - fn source_impl() { - let var = enum_defvariant_list().unwrap() - <|> - .nth(92) - .unwrap(); - } - ", - r" - fn source_impl() { - let var = enum_defvariant_list().unwrap() - . - .nth(92) - .unwrap(); - } - ", - ); - } - - #[test] - fn dont_indent_freestanding_dot() { - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - . - } - ", - ); - type_dot( - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - <|> - } - ", - r" - pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { - . - } - ", - ); - } - #[test] fn test_on_enter() { fn apply_on_enter(before: &str) -> Option { @@ -454,4 +250,214 @@ impl S { ); do_check_noop(r"<|>//! docz"); } + + fn do_type_char(char_typed: char, before: &str) -> Option<(String, SingleFileChange)> { + let (offset, before) = extract_offset(before); + let edit = TextEdit::insert(offset, char_typed.to_string()); + let before = edit.apply(&before); + let parse = SourceFile::parse(&before); + on_char_typed_inner(&parse.tree(), offset, char_typed) + .map(|it| (it.edit.apply(&before), it)) + } + + fn type_char(char_typed: char, before: &str, after: &str) { + let (actual, file_change) = do_type_char(char_typed, before) + .expect(&format!("typing `{}` did nothing", char_typed)); + + if after.contains("<|>") { + let (offset, after) = extract_offset(after); + assert_eq_text!(&after, &actual); + assert_eq!(file_change.cursor_position, Some(offset)) + } else { + assert_eq_text!(after, &actual); + } + } + + fn type_char_noop(char_typed: char, before: &str) { + let file_change = do_type_char(char_typed, before); + assert!(file_change.is_none()) + } + + #[test] + fn test_on_eq_typed() { + // do_check(r" + // fn foo() { + // let foo =<|> + // } + // ", r" + // fn foo() { + // let foo =; + // } + // "); + type_char( + '=', + r" +fn foo() { + let foo <|> 1 + 1 +} +", + r" +fn foo() { + let foo = 1 + 1; +} +", + ); + // do_check(r" + // fn foo() { + // let foo =<|> + // let bar = 1; + // } + // ", r" + // fn foo() { + // let foo =; + // let bar = 1; + // } + // "); + } + + #[test] + fn indents_new_chain_call() { + type_char( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + <|> + } + ", + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + . + } + ", + ); + type_char_noop( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + <|> + } + ", + ) + } + + #[test] + fn indents_new_chain_call_with_semi() { + type_char( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + <|>; + } + ", + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + .; + } + ", + ); + type_char_noop( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + <|>; + } + ", + ) + } + + #[test] + fn indents_continued_chain_call() { + type_char( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + .first() + <|> + } + ", + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + .first() + . + } + ", + ); + type_char_noop( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + self.child_impl(db, name) + .first() + <|> + } + ", + ); + } + + #[test] + fn indents_middle_of_chain_call() { + type_char( + '.', + r" + fn source_impl() { + let var = enum_defvariant_list().unwrap() + <|> + .nth(92) + .unwrap(); + } + ", + r" + fn source_impl() { + let var = enum_defvariant_list().unwrap() + . + .nth(92) + .unwrap(); + } + ", + ); + type_char_noop( + '.', + r" + fn source_impl() { + let var = enum_defvariant_list().unwrap() + <|> + .nth(92) + .unwrap(); + } + ", + ); + } + + #[test] + fn dont_indent_freestanding_dot() { + type_char_noop( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + <|> + } + ", + ); + type_char_noop( + '.', + r" + pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable> { + <|> + } + ", + ); + } + + #[test] + fn adds_space_after_return_type() { + type_char('>', "fn foo() -<|>{ 92 }", "fn foo() -><|> { 92 }") + } } diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 30bcbd7a820a..eea0965edbea 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs @@ -38,7 +38,7 @@ pub fn server_capabilities() -> ServerCapabilities { document_range_formatting_provider: None, document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { first_trigger_character: "=".to_string(), - more_trigger_character: Some(vec![".".to_string()]), + more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), }), selection_range_provider: Some(GenericCapability::default()), folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 530c4d8b6086..6f1e59b4b267 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -132,6 +132,7 @@ pub fn handle_on_enter( } } +// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`. pub fn handle_on_type_formatting( world: WorldSnapshot, params: req::DocumentOnTypeFormattingParams, From d5cd8b5be2a146abe75c0aa322f2313240c8f23c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 13:03:57 +0300 Subject: [PATCH 010/102] disable the new typing handler for `->` It doesn't actually work with LSP --- crates/ra_lsp_server/src/main_loop/handlers.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 6f1e59b4b267..16fb0726600a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -146,6 +146,15 @@ pub fn handle_on_type_formatting( // `text.char_at(position) == typed_char`. position.offset = position.offset - TextUnit::of_char('.'); let char_typed = params.ch.chars().next().unwrap_or('\0'); + + // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, + // but it requires precise cursor positioning to work, and one can't + // position the cursor with on_type formatting. So, let's just toggle this + // feature off here, hoping that we'll enable it one day, 😿. + if char_typed == '>' { + return Ok(None); + } + let edit = world.analysis().on_char_typed(position, char_typed)?; let mut edit = match edit { Some(it) => it, From 27a0cb302577f3bc289c06ce5bc82a5c6e43538d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 25 Oct 2019 13:33:14 +0300 Subject: [PATCH 011/102] Specify working chalk revisions in manifest --- Cargo.lock | 46 ++++++++++++++++++++-------------------- crates/ra_hir/Cargo.toml | 6 +++--- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c902caeb4d7f..382eb92e4c4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-engine" version = "0.9.0" -source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" dependencies = [ - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -136,17 +136,17 @@ dependencies = [ [[package]] name = "chalk-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "chalk-macros" version = "0.1.1" -source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -154,22 +154,22 @@ dependencies = [ [[package]] name = "chalk-rust-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", ] [[package]] name = "chalk-solve" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -979,9 +979,9 @@ name = "ra_hir" version = "0.1.0" dependencies = [ "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", - "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1794,11 +1794,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)" = "" -"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "" -"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)" = "" -"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "" -"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "" +"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" +"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" +"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" +"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" +"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 54c09788aa0a..dce897d3013d 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -22,9 +22,9 @@ tt = { path = "../ra_tt", package = "ra_tt" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } -chalk-solve = { git = "https://github.com/rust-lang/chalk.git" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } lalrpop-intern = "0.15.1" [dev-dependencies] From 0dd35ff2b2ceffdb926953fdacc7d30e1968047d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 14:16:46 +0300 Subject: [PATCH 012/102] auto-generate assists docs and tests --- crates/ra_assists/src/assists/early_return.rs | 43 +++--- crates/ra_assists/src/doc_tests.rs | 23 ++++ crates/ra_assists/src/doc_tests/generated.rs | 27 ++++ crates/ra_assists/src/lib.rs | 4 +- docs/user/assists.md | 24 ++++ docs/user/features.md | 4 +- xtask/src/codegen.rs | 36 ++++- xtask/src/codegen/gen_assists_docs.rs | 123 ++++++++++++++++++ xtask/src/codegen/gen_syntax.rs | 25 +--- xtask/src/main.rs | 1 + xtask/tests/tidy-tests/cli.rs | 7 + xtask/tests/tidy-tests/docs.rs | 4 +- 12 files changed, 269 insertions(+), 52 deletions(-) create mode 100644 crates/ra_assists/src/doc_tests.rs create mode 100644 crates/ra_assists/src/doc_tests/generated.rs create mode 100644 docs/user/assists.md create mode 100644 xtask/src/codegen/gen_assists_docs.rs diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index f7d7e12e73c9..b3d0253406c7 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -1,26 +1,3 @@ -//! Assist: `convert_to_guarded_return` -//! -//! Replace a large conditional with a guarded return. -//! -//! ```text -//! fn <|>main() { -//! if cond { -//! foo(); -//! bar(); -//! } -//! } -//! ``` -//! -> -//! ```text -//! fn main() { -//! if !cond { -//! return; -//! } -//! foo(); -//! bar(); -//! } -//! ``` - use std::ops::RangeInclusive; use hir::db::HirDatabase; @@ -36,6 +13,26 @@ use crate::{ AssistId, }; +// Assist: convert_to_guarded_return +// Replace a large conditional with a guarded return. +// ``` +// fn main() { +// <|>if cond { +// foo(); +// bar(); +// } +// } +// ``` +// -> +// ``` +// fn main() { +// if !cond { +// return; +// } +// foo(); +// bar(); +// } +// ``` pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.node_at_offset()?; let expr = if_expr.condition()?.expr()?; diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs new file mode 100644 index 000000000000..88e901517c27 --- /dev/null +++ b/crates/ra_assists/src/doc_tests.rs @@ -0,0 +1,23 @@ +//! Each assist definition has a special comment, which specifies docs and +//! example. +//! +//! We collect all the example and write the as tests in this module. + +mod generated; + +use hir::mock::MockDatabase; +use ra_db::FileRange; +use ra_syntax::TextRange; +use test_utils::{assert_eq_text, extract_offset}; + +fn check(assist_id: &str, before: &str, after: &str) { + let (before_cursor_pos, before) = extract_offset(before); + let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); + let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; + + let (_assist_id, action) = + crate::assists(&db, frange).into_iter().find(|(id, _)| id.id.0 == assist_id).unwrap(); + + let actual = action.edit.apply(&before); + assert_eq_text!(after, &actual); +} diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs new file mode 100644 index 000000000000..e5f6910f1152 --- /dev/null +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -0,0 +1,27 @@ +//! Generated file, do not edit by hand, see `crate/ra_tools/src/codegen` + +use super::check; + +#[test] +fn doctest_convert_to_guarded_return() { + check( + "convert_to_guarded_return", + r#####" +fn main() { + <|>if cond { + foo(); + bar(); + } +} +"#####, + r#####" +fn main() { + if !cond { + return; + } + foo(); + bar(); +} +"#####, + ) +} diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index ab77b46a9977..de576324fbeb 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -7,6 +7,8 @@ mod assist_ctx; mod marks; +#[cfg(test)] +mod doc_tests; use hir::db::HirDatabase; use itertools::Itertools; @@ -36,7 +38,7 @@ pub struct AssistAction { pub target: Option, } -/// Return all the assists eapplicable at the given position. +/// Return all the assists applicable at the given position. /// /// Assists are returned in the "unresolved" state, that is only labels are /// returned, without actual edits. diff --git a/docs/user/assists.md b/docs/user/assists.md new file mode 100644 index 000000000000..cb4b0b9fb83f --- /dev/null +++ b/docs/user/assists.md @@ -0,0 +1,24 @@ +# Assists + +## `convert_to_guarded_return` + +Replace a large conditional with a guarded return. + +```rust +// BEFORE +fn main() { + <|>if cond { + foo(); + bar(); + } +} + +// AFTER +fn main() { + if !cond { + return; + } + foo(); + bar(); +} +``` diff --git a/docs/user/features.md b/docs/user/features.md index 8b7a8d7fc189..a94b65ad4da5 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -97,11 +97,13 @@ Start `cargo watch` for live error highlighting. Will prompt to install if it's Stop `cargo watch` -### Code Actions (Assists) +### Assists (Code Actions) These are triggered in a particular context via light bulb. We use custom code on the VS Code side to be able to position cursor. `<|>` signifies cursor +See [assists.md](./assists.md) + - Add `#[derive]` ```rust diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index bf3a9011950d..44729cd57aad 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs @@ -7,12 +7,22 @@ mod gen_syntax; mod gen_parser_tests; +mod gen_assists_docs; -use std::{fs, mem, path::Path}; +use std::{ + fs, + io::Write, + mem, + path::Path, + process::{Command, Stdio}, +}; -use crate::Result; +use crate::{project_root, Result}; -pub use self::{gen_parser_tests::generate_parser_tests, gen_syntax::generate_syntax}; +pub use self::{ + gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, + gen_syntax::generate_syntax, +}; pub const GRAMMAR: &str = "crates/ra_syntax/src/grammar.ron"; const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar"; @@ -22,6 +32,10 @@ const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err pub const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs"; pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs"; +const ASSISTS_DIR: &str = "crates/ra_assists/src/assists"; +const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs"; +const ASSISTS_DOCS: &str = "docs/user/assists.md"; + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Mode { Overwrite, @@ -30,7 +44,7 @@ pub enum Mode { /// A helper to update file on disk if it has changed. /// With verify = false, -pub fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { +fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { match fs::read_to_string(path) { Ok(ref old_contents) if old_contents == contents => { return Ok(()); @@ -45,6 +59,20 @@ pub fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { Ok(()) } +fn reformat(text: impl std::fmt::Display) -> Result { + let mut rustfmt = Command::new("rustfmt") + .arg("--config-path") + .arg(project_root().join("rustfmt.toml")) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + write!(rustfmt.stdin.take().unwrap(), "{}", text)?; + let output = rustfmt.wait_with_output()?; + let stdout = String::from_utf8(output.stdout)?; + let preamble = "Generated file, do not edit by hand, see `crate/ra_tools/src/codegen`"; + Ok(format!("//! {}\n\n{}", preamble, stdout)) +} + fn extract_comment_blocks(text: &str) -> Vec> { let mut res = Vec::new(); diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs new file mode 100644 index 000000000000..654ae09d6692 --- /dev/null +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -0,0 +1,123 @@ +use std::{fs, path::Path}; + +use crate::{ + codegen::{self, extract_comment_blocks, Mode}, + project_root, Result, +}; + +pub fn generate_assists_docs(mode: Mode) -> Result<()> { + let assists = collect_assists()?; + generate_tests(&assists, mode)?; + generate_docs(&assists, mode)?; + Ok(()) +} + +#[derive(Debug)] +struct Assist { + id: String, + doc: String, + before: String, + after: String, +} + +fn collect_assists() -> Result> { + let mut res = Vec::new(); + for entry in fs::read_dir(project_root().join(codegen::ASSISTS_DIR))? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + collect_file(&mut res, path.as_path())?; + } + } + res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); + return Ok(res); + + fn collect_file(acc: &mut Vec, path: &Path) -> Result<()> { + let text = fs::read_to_string(path)?; + let comment_blocks = extract_comment_blocks(&text); + + for block in comment_blocks { + // FIXME: doesn't support blank lines yet, need to tweak + // `extract_comment_blocks` for that. + let mut lines = block.iter(); + let first_line = lines.next().unwrap(); + if !first_line.starts_with("Assist: ") { + continue; + } + let id = first_line["Assist: ".len()..].to_string(); + assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_')); + + let doc = take_until(lines.by_ref(), "```"); + let before = take_until(lines.by_ref(), "```"); + + assert_eq!(lines.next().unwrap().as_str(), "->"); + assert_eq!(lines.next().unwrap().as_str(), "```"); + let after = take_until(lines.by_ref(), "```"); + acc.push(Assist { id, doc, before, after }) + } + + fn take_until<'a>(lines: impl Iterator, marker: &str) -> String { + let mut buf = Vec::new(); + for line in lines { + if line == marker { + break; + } + buf.push(line.clone()); + } + buf.join("\n") + } + Ok(()) + } +} + +fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { + let mut buf = String::from("use super::check;\n"); + + for assist in assists.iter() { + let test = format!( + r######" +#[test] +fn doctest_{}() {{ + check( + "{}", +r#####" +{} +"#####, r#####" +{} +"#####) +}} +"######, + assist.id, assist.id, assist.before, assist.after + ); + + buf.push_str(&test) + } + let buf = codegen::reformat(buf)?; + codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) +} + +fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { + let mut buf = String::from("# Assists\n"); + + for assist in assists { + let docs = format!( + " +## `{}` + +{} + +```rust +// BEFORE +{} + +// AFTER +{} +``` +", + assist.id, assist.doc, assist.before, assist.after + ); + buf.push_str(&docs); + } + + codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode) +} diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 6a81c0e4dfdb..88f2ac0e35e2 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs @@ -3,12 +3,7 @@ //! Specifically, it generates the `SyntaxKind` enum and a number of newtype //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. -use std::{ - collections::BTreeMap, - fs, - io::Write, - process::{Command, Stdio}, -}; +use std::{collections::BTreeMap, fs}; use proc_macro2::{Punct, Spacing}; use quote::{format_ident, quote}; @@ -163,7 +158,7 @@ fn generate_ast(grammar: &Grammar) -> Result { #(#nodes)* }; - let pretty = reformat(ast)?; + let pretty = codegen::reformat(ast)?; Ok(pretty) } @@ -276,21 +271,7 @@ fn generate_syntax_kinds(grammar: &Grammar) -> Result { } }; - reformat(ast) -} - -fn reformat(text: impl std::fmt::Display) -> Result { - let mut rustfmt = Command::new("rustfmt") - .arg("--config-path") - .arg(project_root().join("rustfmt.toml")) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - write!(rustfmt.stdin.take().unwrap(), "{}", text)?; - let output = rustfmt.wait_with_output()?; - let stdout = String::from_utf8(output.stdout)?; - let preamble = "Generated file, do not edit by hand, see `crate/ra_tools/src/codegen`"; - Ok(format!("//! {}\n\n{}", preamble, stdout)) + codegen::reformat(ast) } #[derive(Deserialize, Debug)] diff --git a/xtask/src/main.rs b/xtask/src/main.rs index db901ced2632..06aa3c8ecaa0 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -64,6 +64,7 @@ fn main() -> Result<()> { } codegen::generate_syntax(Mode::Overwrite)?; codegen::generate_parser_tests(Mode::Overwrite)?; + codegen::generate_assists_docs(Mode::Overwrite)?; } "format" => { if matches.contains(["-h", "--help"]) { diff --git a/xtask/tests/tidy-tests/cli.rs b/xtask/tests/tidy-tests/cli.rs index 543c7d7c4538..573ffadbf8ee 100644 --- a/xtask/tests/tidy-tests/cli.rs +++ b/xtask/tests/tidy-tests/cli.rs @@ -18,6 +18,13 @@ fn generated_tests_are_fresh() { } } +#[test] +fn generated_assists_are_fresh() { + if let Err(error) = codegen::generate_assists_docs(Mode::Verify) { + panic!("{}. Please update assists by running `cargo xtask codegen`", error); + } +} + #[test] fn check_code_formatting() { if let Err(error) = run_rustfmt(Mode::Verify) { diff --git a/xtask/tests/tidy-tests/docs.rs b/xtask/tests/tidy-tests/docs.rs index fe5852bc6281..b766aeff16de 100644 --- a/xtask/tests/tidy-tests/docs.rs +++ b/xtask/tests/tidy-tests/docs.rs @@ -8,7 +8,9 @@ use walkdir::{DirEntry, WalkDir}; use xtask::project_root; fn is_exclude_dir(p: &Path) -> bool { - let exclude_dirs = ["tests", "test_data"]; + // Test hopefully don't really need comments, and for assists we already + // have special comments which are source of doc tests and user docs. + let exclude_dirs = ["tests", "test_data", "assists"]; let mut cur_path = p; while let Some(path) = cur_path.parent() { if exclude_dirs.iter().any(|dir| path.ends_with(dir)) { From 813b725957efe64b06316f524419328b6c152f73 Mon Sep 17 00:00:00 2001 From: Jacob Date: Fri, 25 Oct 2019 11:32:31 -0700 Subject: [PATCH 013/102] sublime: hint where feature flags would go --- docs/user/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/user/README.md b/docs/user/README.md index a1cef22cc6a3..eb1d5ed141ec 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -182,7 +182,11 @@ Installation: "syntaxes": [ "Packages/Rust/Rust.sublime-syntax", "Packages/Rust Enhanced/RustEnhanced.sublime-syntax" - ] + ], + "initializationOptions": { + "featureFlags": { + } + }, } ``` From d385438bcc8d302fbcb91114e19ac0cc30528822 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 25 Oct 2019 23:38:15 +0300 Subject: [PATCH 014/102] generate more assists docs --- crates/ra_assists/src/assists/add_derive.rs | 18 ++- .../src/assists/add_explicit_type.rs | 16 +- crates/ra_assists/src/assists/add_impl.rs | 19 ++- .../src/assists/add_missing_impl_members.rs | 58 +++++++- .../ra_assists/src/assists/apply_demorgan.rs | 26 ++-- crates/ra_assists/src/doc_tests.rs | 6 +- crates/ra_assists/src/doc_tests/generated.rs | 139 ++++++++++++++++++ docs/user/assists.md | 137 +++++++++++++++++ docs/user/features.md | 91 ------------ xtask/src/codegen.rs | 13 ++ xtask/src/codegen/gen_assists_docs.rs | 10 +- 11 files changed, 419 insertions(+), 114 deletions(-) diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index 77ecc33c9d9f..d3ba634c4018 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ ast::{self, AstNode, AttrsOwner}, @@ -9,6 +7,22 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; +// Assist: add_derive +// Adds a new `#[derive()]` clause to a struct or enum. +// ``` +// struct Point { +// x: u32, +// y: u32,<|> +// } +// ``` +// -> +// ``` +// #[derive()] +// struct Point { +// x: u32, +// y: u32, +// } +// ``` pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option { let nominal = ctx.node_at_offset::()?; let node_start = derive_insertion_offset(&nominal)?; diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 8c83dc9878c3..33b7bea7f2b1 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::{db::HirDatabase, HirDisplay, Ty}; use ra_syntax::{ ast::{self, AstNode, LetStmt, NameOwner}, @@ -8,7 +6,19 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; -/// Add explicit type assist. +// Assist: add_explicit_type +// Specify type for a let binding +// ``` +// fn main() { +// let x<|> = 92; +// } +// ``` +// -> +// ``` +// fn main() { +// let x: i32 = 92; +// } +// ``` pub(crate) fn add_explicit_type(mut ctx: AssistCtx) -> Option { let stmt = ctx.node_at_offset::()?; let expr = stmt.initializer()?; diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 94801fbc9a0e..40bc5c4641d8 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use format_buf::format; use hir::db::HirDatabase; use join_to_string::join; @@ -10,6 +8,23 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; +// Assist: add_impl +// Adds a new inherent impl for a type +// ``` +// struct Ctx { +// data: T,<|> +// } +// ``` +// -> +// ``` +// struct Ctx { +// data: T, +// } +// +// impl Ctx { +// +// } +// ``` pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { let nominal = ctx.node_at_offset::()?; let name = nominal.name()?; diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 565b96fb509f..36fa6f9ea7a5 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::{db::HirDatabase, HasSource}; use ra_syntax::{ ast::{self, edit, make, AstNode, NameOwner}, @@ -14,6 +12,32 @@ enum AddMissingImplMembersMode { NoDefaultMethods, } +// Assist: add_impl_missing_members +// Adds scaffold for required impl members +// ``` +// trait T { +// Type X; +// fn foo(&self); +// fn bar(&self) {} +// } +// +// impl T for () {<|> +// +// } +// ``` +// -> +// ``` +// trait T { +// Type X; +// fn foo(&self); +// fn bar(&self) {} +// } +// +// impl T for () { +// fn foo(&self) { unimplemented!() } +// +// } +// ``` pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Option { add_missing_impl_members_inner( ctx, @@ -23,6 +47,36 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Opti ) } +// Assist: add_impl_default_members +// Adds scaffold for overriding default impl members +// ``` +// trait T { +// Type X; +// fn foo(&self); +// fn bar(&self) {} +// } +// +// impl T for () { +// Type X = (); +// fn foo(&self) {}<|> +// +// } +// ``` +// -> +// ``` +// trait T { +// Type X; +// fn foo(&self); +// fn bar(&self) {} +// } +// +// impl T for () { +// Type X = (); +// fn foo(&self) {} +// fn bar(&self) {} +// +// } +// ``` pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> Option { add_missing_impl_members_inner( ctx, diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 5f2b0dd189b3..a072f63e7a8a 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -1,18 +1,26 @@ -//! This contains the functions associated with the demorgan assist. -//! This assist transforms boolean expressions of the form `!a || !b` into -//! `!(a && b)`. use hir::db::HirDatabase; use ra_syntax::ast::{self, AstNode}; use ra_syntax::SyntaxNode; use crate::{Assist, AssistCtx, AssistId}; -/// Assist for applying demorgan's law -/// -/// This transforms expressions of the form `!l || !r` into `!(l && r)`. -/// This also works with `&&`. This assist can only be applied with the cursor -/// on either `||` or `&&`, with both operands being a negation of some kind. -/// This means something of the form `!x` or `x != y`. +// Assist: apply_demorgan +// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). +// This transforms expressions of the form `!l || !r` into `!(l && r)`. +// This also works with `&&`. This assist can only be applied with the cursor +// on either `||` or `&&`, with both operands being a negation of some kind. +// This means something of the form `!x` or `x != y`. +// ``` +// fn main() { +// if x != 4 ||<|> !y {} +// } +// ``` +// -> +// ``` +// fn main() { +// if !(x == 4 && y) {} +// } +// ``` pub(crate) fn apply_demorgan(mut ctx: AssistCtx) -> Option { let expr = ctx.node_at_offset::()?; let op = expr.op_kind()?; diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 88e901517c27..872bbdf17a5b 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs @@ -15,8 +15,10 @@ fn check(assist_id: &str, before: &str, after: &str) { let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; - let (_assist_id, action) = - crate::assists(&db, frange).into_iter().find(|(id, _)| id.id.0 == assist_id).unwrap(); + let (_assist_id, action) = crate::assists(&db, frange) + .into_iter() + .find(|(id, _)| id.id.0 == assist_id) + .unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id)); let actual = action.edit.apply(&before); assert_eq_text!(after, &actual); diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index e5f6910f1152..76d86b93dadf 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -2,6 +2,145 @@ use super::check; +#[test] +fn doctest_add_derive() { + check( + "add_derive", + r#####" +struct Point { + x: u32, + y: u32,<|> +} +"#####, + r#####" +#[derive()] +struct Point { + x: u32, + y: u32, +} +"#####, + ) +} + +#[test] +fn doctest_add_explicit_type() { + check( + "add_explicit_type", + r#####" +fn main() { + let x<|> = 92; +} +"#####, + r#####" +fn main() { + let x: i32 = 92; +} +"#####, + ) +} + +#[test] +fn doctest_add_impl() { + check( + "add_impl", + r#####" +struct Ctx { + data: T,<|> +} +"#####, + r#####" +struct Ctx { + data: T, +} + +impl Ctx { + +} +"#####, + ) +} + +#[test] +fn doctest_add_impl_default_members() { + check( + "add_impl_default_members", + r#####" +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + Type X = (); + fn foo(&self) {}<|> + +} +"#####, + r#####" +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + Type X = (); + fn foo(&self) {} + fn bar(&self) {} + +} +"#####, + ) +} + +#[test] +fn doctest_add_impl_missing_members() { + check( + "add_impl_missing_members", + r#####" +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () {<|> + +} +"#####, + r#####" +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + fn foo(&self) { unimplemented!() } + +} +"#####, + ) +} + +#[test] +fn doctest_apply_demorgan() { + check( + "apply_demorgan", + r#####" +fn main() { + if x != 4 ||<|> !y {} +} +"#####, + r#####" +fn main() { + if !(x == 4 && y) {} +} +"#####, + ) +} + #[test] fn doctest_convert_to_guarded_return() { check( diff --git a/docs/user/assists.md b/docs/user/assists.md index cb4b0b9fb83f..eeb486832178 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -1,5 +1,142 @@ # Assists +## `add_derive` + +Adds a new `#[derive()]` clause to a struct or enum. + +```rust +// BEFORE +struct Point { + x: u32, + y: u32,<|> +} + +// AFTER +#[derive()] +struct Point { + x: u32, + y: u32, +} +``` + +## `add_explicit_type` + +Specify type for a let binding + +```rust +// BEFORE +fn main() { + let x<|> = 92; +} + +// AFTER +fn main() { + let x: i32 = 92; +} +``` + +## `add_impl` + +Adds a new inherent impl for a type + +```rust +// BEFORE +struct Ctx { + data: T,<|> +} + +// AFTER +struct Ctx { + data: T, +} + +impl Ctx { + +} +``` + +## `add_impl_default_members` + +Adds scaffold for overriding default impl members + +```rust +// BEFORE +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + Type X = (); + fn foo(&self) {}<|> + +} + +// AFTER +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + Type X = (); + fn foo(&self) {} + fn bar(&self) {} + +} +``` + +## `add_impl_missing_members` + +Adds scaffold for required impl members + +```rust +// BEFORE +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () {<|> + +} + +// AFTER +trait T { + Type X; + fn foo(&self); + fn bar(&self) {} +} + +impl T for () { + fn foo(&self) { unimplemented!() } + +} +``` + +## `apply_demorgan` + +Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). +This transforms expressions of the form `!l || !r` into `!(l && r)`. +This also works with `&&`. This assist can only be applied with the cursor +on either `||` or `&&`, with both operands being a negation of some kind. +This means something of the form `!x` or `x != y`. + +```rust +// BEFORE +fn main() { + if x != 4 ||<|> !y {} +} + +// AFTER +fn main() { + if !(x == 4 && y) {} +} +``` + ## `convert_to_guarded_return` Replace a large conditional with a guarded return. diff --git a/docs/user/features.md b/docs/user/features.md index a94b65ad4da5..acf092cec1bb 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -104,84 +104,6 @@ the VS Code side to be able to position cursor. `<|>` signifies cursor See [assists.md](./assists.md) -- Add `#[derive]` - -```rust -// before: -struct Foo { - <|>x: i32 -} -// after: -#[derive(<|>)] -struct Foo { - x: i32 -} -``` - -- Add `impl` - -```rust -// before: -struct Foo<'a, T: Debug> { - <|>t: T -} -// after: -struct Foo<'a, T: Debug> { - t: T -} - -impl<'a, T: Debug> Foo<'a, T> { - <|> -} -``` - -- Add missing `impl` members - -```rust -// before: -trait Foo { - fn foo(&self); - fn bar(&self); - fn baz(&self); -} - -struct S; - -impl Foo for S { - fn bar(&self) {} - <|> -} - -// after: -trait Foo { - fn foo(&self); - fn bar(&self); - fn baz(&self); -} - -struct S; - -impl Foo for S { - fn bar(&self) {} - fn foo(&self) { unimplemented!() } - fn baz(&self) { unimplemented!() }<|> -} -``` - -- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) - -```rust -// before: -fn example(x: bool) -> bool { - !x || !x -} - -// after: -fn example(x: bool) -> bool { - !(x && x) -} -``` - - Import path ```rust @@ -391,19 +313,6 @@ fn foo() { } ``` -- Add explicit type - -```rust -// before: -fn foo() { - let t<|> = (&2, Some(1)); -} -// after: -fn foo() { - let t<|>: (&i32, Option) = (&2, Some(1)); -} -``` - - Move guard expression to match arm body ```rust // before: diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index 44729cd57aad..4ec8ab75af5c 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs @@ -74,6 +74,14 @@ fn reformat(text: impl std::fmt::Display) -> Result { } fn extract_comment_blocks(text: &str) -> Vec> { + do_extract_comment_blocks(text, false) +} + +fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec> { + do_extract_comment_blocks(text, true) +} + +fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> Vec> { let mut res = Vec::new(); let prefix = "// "; @@ -81,6 +89,11 @@ fn extract_comment_blocks(text: &str) -> Vec> { let mut block = vec![]; for line in lines { + if line == "//" && allow_blocks_with_empty_lins { + block.push(String::new()); + continue; + } + let is_comment = line.starts_with(prefix); if is_comment { block.push(line[prefix.len()..].to_string()); diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 654ae09d6692..e313820d18a5 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -1,7 +1,7 @@ use std::{fs, path::Path}; use crate::{ - codegen::{self, extract_comment_blocks, Mode}, + codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, project_root, Result, }; @@ -34,7 +34,7 @@ fn collect_assists() -> Result> { fn collect_file(acc: &mut Vec, path: &Path) -> Result<()> { let text = fs::read_to_string(path)?; - let comment_blocks = extract_comment_blocks(&text); + let comment_blocks = extract_comment_blocks_with_empty_lines(&text); for block in comment_blocks { // FIXME: doesn't support blank lines yet, need to tweak @@ -45,7 +45,11 @@ fn collect_assists() -> Result> { continue; } let id = first_line["Assist: ".len()..].to_string(); - assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_')); + assert!( + id.chars().all(|it| it.is_ascii_lowercase() || it == '_'), + "invalid assist id: {:?}", + id + ); let doc = take_until(lines.by_ref(), "```"); let before = take_until(lines.by_ref(), "```"); From b342ee561697d9925e7ee07cd5b56fd029562c94 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 15 Oct 2019 21:03:34 +0200 Subject: [PATCH 015/102] Upgrade Chalk (without using its dyn/impl Trait support) --- Cargo.lock | 46 +++++------ crates/ra_hir/Cargo.toml | 6 +- crates/ra_hir/src/ty/traits.rs | 6 +- crates/ra_hir/src/ty/traits/chalk.rs | 110 +++++++++++++++++---------- 4 files changed, 99 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 382eb92e4c4f..6f8a4431d5a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-engine" version = "0.9.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" dependencies = [ - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -136,17 +136,17 @@ dependencies = [ [[package]] name = "chalk-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "chalk-macros" version = "0.1.1" -source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -154,22 +154,22 @@ dependencies = [ [[package]] name = "chalk-rust-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", ] [[package]] name = "chalk-solve" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9#13303bb0067c6ed0572322080ae367ee38f9e7c9" +source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -979,9 +979,9 @@ name = "ra_hir" version = "0.1.0" dependencies = [ "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", - "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1794,11 +1794,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" -"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" -"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" -"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" -"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=13303bb0067c6ed0572322080ae367ee38f9e7c9)" = "" +"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" +"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" +"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" +"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" +"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index dce897d3013d..f05ec0b8a730 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -22,9 +22,9 @@ tt = { path = "../ra_tt", package = "ra_tt" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "13303bb0067c6ed0572322080ae367ee38f9e7c9" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } lalrpop-intern = "0.15.1" [dev-dependencies] diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 0cb5c37984b5..4f1eab1508af 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -1,7 +1,7 @@ //! Trait solving using Chalk. use std::sync::{Arc, Mutex}; -use chalk_ir::cast::Cast; +use chalk_ir::{cast::Cast, family::ChalkIr}; use log::debug; use ra_db::salsa; use ra_prof::profile; @@ -33,7 +33,7 @@ impl TraitSolver { fn solve( &self, db: &impl HirDatabase, - goal: &chalk_ir::UCanonical>, + goal: &chalk_ir::UCanonical>>, ) -> Option { let context = ChalkContext { db, krate: self.krate }; debug!("solve goal: {:?}", goal); @@ -196,7 +196,7 @@ pub(crate) fn trait_solve_query( } fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { - let convert_subst = |subst: chalk_ir::Canonical| { + let convert_subst = |subst: chalk_ir::Canonical>| { let value = subst .value .parameters diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 00aaf65d92a6..ad7c11a5a83d 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use log::debug; use chalk_ir::{ - cast::Cast, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, TypeKindId, TypeName, - UniverseIndex, + cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, + TypeKindId, TypeName, UniverseIndex, }; use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; @@ -38,8 +38,8 @@ where } impl ToChalk for Ty { - type Chalk = chalk_ir::Ty; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { + type Chalk = chalk_ir::Ty; + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { match self { Ty::Apply(apply_ty) => { let name = match apply_ty.ctor { @@ -62,21 +62,21 @@ impl ToChalk for Ty { chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() } Ty::Param { idx, .. } => { - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() + PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::() } Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), // FIXME this is clearly incorrect, but probably not too incorrect // and I'm not sure what to actually do with Ty::Unknown // maybe an alternative would be `for T`? (meaningless in rust, but expressible in chalk's Ty) - // - // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet + // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() + PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() } + .to_ty::() } } } - fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { + fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { match chalk { chalk_ir::Ty::Apply(apply_ty) => { // FIXME this is kind of hacky due to the fact that @@ -108,18 +108,30 @@ impl ToChalk for Ty { chalk_ir::Ty::ForAll(_) => unimplemented!(), chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, + chalk_ir::Ty::Dyn(where_clauses) => { + assert_eq!(where_clauses.binders.len(), 1); + let predicates = + where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); + Ty::Dyn(predicates) + } + chalk_ir::Ty::Opaque(where_clauses) => { + assert_eq!(where_clauses.binders.len(), 1); + let predicates = + where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); + Ty::Opaque(predicates) + } } } } impl ToChalk for Substs { - type Chalk = Vec; + type Chalk = Vec>; - fn to_chalk(self, db: &impl HirDatabase) -> Vec { + fn to_chalk(self, db: &impl HirDatabase) -> Vec> { self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() } - fn from_chalk(db: &impl HirDatabase, parameters: Vec) -> Substs { + fn from_chalk(db: &impl HirDatabase, parameters: Vec>) -> Substs { let tys = parameters .into_iter() .map(|p| match p { @@ -132,15 +144,15 @@ impl ToChalk for Substs { } impl ToChalk for TraitRef { - type Chalk = chalk_ir::TraitRef; + type Chalk = chalk_ir::TraitRef; - fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { + fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { let trait_id = self.trait_.to_chalk(db); let parameters = self.substs.to_chalk(db); chalk_ir::TraitRef { trait_id, parameters } } - fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { + fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { let trait_ = from_chalk(db, trait_ref.trait_id); let substs = from_chalk(db, trait_ref.parameters); TraitRef { trait_, substs } @@ -196,9 +208,9 @@ impl ToChalk for TypeAlias { } impl ToChalk for GenericPredicate { - type Chalk = chalk_ir::QuantifiedWhereClause; + type Chalk = chalk_ir::QuantifiedWhereClause; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { match self { GenericPredicate::Implemented(trait_ref) => { make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) @@ -221,25 +233,40 @@ impl ToChalk for GenericPredicate { } fn from_chalk( - _db: &impl HirDatabase, - _where_clause: chalk_ir::QuantifiedWhereClause, + db: &impl HirDatabase, + where_clause: chalk_ir::QuantifiedWhereClause, ) -> GenericPredicate { - // This should never need to be called - unimplemented!() + match where_clause.value { + chalk_ir::WhereClause::Implemented(tr) => { + if tr.trait_id == UNKNOWN_TRAIT { + // FIXME we need an Error enum on the Chalk side to avoid this + return GenericPredicate::Error; + } + GenericPredicate::Implemented(from_chalk(db, tr)) + } + chalk_ir::WhereClause::ProjectionEq(projection_eq) => { + let projection_ty = from_chalk(db, projection_eq.projection); + let ty = from_chalk(db, projection_eq.ty); + GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty }) + } + } } } impl ToChalk for ProjectionTy { - type Chalk = chalk_ir::ProjectionTy; + type Chalk = chalk_ir::ProjectionTy; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { chalk_ir::ProjectionTy { associated_ty_id: self.associated_ty.to_chalk(db), parameters: self.parameters.to_chalk(db), } } - fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy { + fn from_chalk( + db: &impl HirDatabase, + projection_ty: chalk_ir::ProjectionTy, + ) -> ProjectionTy { ProjectionTy { associated_ty: from_chalk(db, projection_ty.associated_ty_id), parameters: from_chalk(db, projection_ty.parameters), @@ -248,31 +275,31 @@ impl ToChalk for ProjectionTy { } impl ToChalk for super::ProjectionPredicate { - type Chalk = chalk_ir::Normalize; + type Chalk = chalk_ir::Normalize; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { chalk_ir::Normalize { projection: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db), } } - fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { + fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { unimplemented!() } } impl ToChalk for Obligation { - type Chalk = chalk_ir::DomainGoal; + type Chalk = chalk_ir::DomainGoal; - fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { match self { Obligation::Trait(tr) => tr.to_chalk(db).cast(), Obligation::Projection(pr) => pr.to_chalk(db).cast(), } } - fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { + fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { unimplemented!() } } @@ -296,16 +323,16 @@ where } impl ToChalk for Arc { - type Chalk = Arc; + type Chalk = Arc>; - fn to_chalk(self, db: &impl HirDatabase) -> Arc { + fn to_chalk(self, db: &impl HirDatabase) -> Arc> { let mut clauses = Vec::new(); for pred in &self.predicates { if pred.is_error() { // for env, we just ignore errors continue; } - let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); + let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); clauses.push(program_clause.into_from_env_clause()); } chalk_ir::Environment::new().add_clauses(clauses) @@ -313,13 +340,16 @@ impl ToChalk for Arc { fn from_chalk( _db: &impl HirDatabase, - _env: Arc, + _env: Arc>, ) -> Arc { unimplemented!() } } -impl ToChalk for super::InEnvironment { +impl ToChalk for super::InEnvironment +where + T::Chalk: chalk_ir::family::HasTypeFamily, +{ type Chalk = chalk_ir::InEnvironment; fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment { @@ -351,7 +381,7 @@ fn convert_where_clauses( db: &impl HirDatabase, def: GenericDef, substs: &Substs, -) -> Vec { +) -> Vec> { let generic_predicates = db.generic_predicates(def); let mut result = Vec::with_capacity(generic_predicates.len()); for pred in generic_predicates.iter() { @@ -384,7 +414,7 @@ where fn impls_for_trait( &self, trait_id: chalk_ir::TraitId, - parameters: &[Parameter], + parameters: &[Parameter], ) -> Vec { debug!("impls_for_trait {:?}", trait_id); if trait_id == UNKNOWN_TRAIT { @@ -430,13 +460,13 @@ where } fn split_projection<'p>( &self, - projection: &'p chalk_ir::ProjectionTy, - ) -> (Arc, &'p [Parameter], &'p [Parameter]) { + projection: &'p chalk_ir::ProjectionTy, + ) -> (Arc, &'p [Parameter], &'p [Parameter]) { debug!("split_projection {:?}", projection); // we don't support GATs, so I think this should always be correct currently (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) } - fn custom_clauses(&self) -> Vec { + fn custom_clauses(&self) -> Vec> { vec![] } fn local_impls_to_coherence_check( From 8e8b6e7f628824d8bf5a50f6b8d445447c000830 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 17:12:56 +0300 Subject: [PATCH 016/102] warn if npm is not found --- xtask/src/main.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 06aa3c8ecaa0..eb39bf7159a2 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -159,6 +159,17 @@ fn fix_path_for_mac() -> Result<()> { } fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { + let npm_version = Cmd { + unix: r"npm --version", + windows: r"cmd.exe /c npm.cmd --version", + work_dir: "./editors/code", + } + .run(); + + if npm_version.is_err() { + eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin") + } + Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?; Cmd { unix: r"npm run package", From e3a253d80f124f12b5ec3707216590eb5c0dccff Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 17:20:44 +0300 Subject: [PATCH 017/102] document tasks module --- xtask/src/main.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 06aa3c8ecaa0..34eb63eb3486 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,5 +1,12 @@ -//! FIXME: write short doc here - +//! See https://github.com/matklad/cargo-xtask/. +//! +//! This binary defines various auxiliary build commands, which are not +//! expressible with just `cargo`. Notably, it provides `cargo xtask codegen` +//! for code genetaiont and `cargo xtask install` for installation of +//! rust-analyzer server and client. +//! +//! This binary is integrated into the `cargo` command line by using an alias in +//! `.cargo/config`. mod help; use core::fmt::Write; From 394e4744792f8e36ca1690cb23c2d3dd55556272 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 17:27:47 +0300 Subject: [PATCH 018/102] add blank lines for readability --- crates/ra_assists/src/assists/add_derive.rs | 2 ++ crates/ra_assists/src/assists/add_explicit_type.rs | 2 ++ crates/ra_assists/src/assists/add_impl.rs | 2 ++ crates/ra_assists/src/assists/add_missing_impl_members.rs | 2 ++ crates/ra_assists/src/assists/apply_demorgan.rs | 2 ++ xtask/src/codegen/gen_assists_docs.rs | 2 +- 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index d3ba634c4018..b077acb8142a 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs @@ -8,7 +8,9 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; // Assist: add_derive +// // Adds a new `#[derive()]` clause to a struct or enum. +// // ``` // struct Point { // x: u32, diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 33b7bea7f2b1..302b95579083 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -7,7 +7,9 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; // Assist: add_explicit_type +// // Specify type for a let binding +// // ``` // fn main() { // let x<|> = 92; diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 40bc5c4641d8..43aeac7bd6e7 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -9,7 +9,9 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; // Assist: add_impl +// // Adds a new inherent impl for a type +// // ``` // struct Ctx { // data: T,<|> diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 36fa6f9ea7a5..fe1f2e72e7f5 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -13,7 +13,9 @@ enum AddMissingImplMembersMode { } // Assist: add_impl_missing_members +// // Adds scaffold for required impl members +// // ``` // trait T { // Type X; diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index a072f63e7a8a..75144cefe2e0 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -5,11 +5,13 @@ use ra_syntax::SyntaxNode; use crate::{Assist, AssistCtx, AssistId}; // Assist: apply_demorgan +// // Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). // This transforms expressions of the form `!l || !r` into `!(l && r)`. // This also works with `&&`. This assist can only be applied with the cursor // on either `||` or `&&`, with both operands being a negation of some kind. // This means something of the form `!x` or `x != y`. +// // ``` // fn main() { // if x != 4 ||<|> !y {} diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index e313820d18a5..2ca7cda63dbe 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -51,7 +51,7 @@ fn collect_assists() -> Result> { id ); - let doc = take_until(lines.by_ref(), "```"); + let doc = take_until(lines.by_ref(), "```").trim().to_string(); let before = take_until(lines.by_ref(), "```"); assert_eq!(lines.next().unwrap().as_str(), "->"); From 3126152a84e08a80659d49d735d03628154564ed Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 17:37:04 +0300 Subject: [PATCH 019/102] document a couple of assists --- .../src/assists/change_visibility.rs | 13 ++++- .../ra_assists/src/assists/fill_match_arms.rs | 24 +++++++++ crates/ra_assists/src/doc_tests/generated.rs | 39 ++++++++++++++ docs/user/assists.md | 37 ++++++++++++++ docs/user/features.md | 51 ------------------- 5 files changed, 111 insertions(+), 53 deletions(-) diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index df92c6b67c99..88118cdf7c04 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ ast::{self, NameOwner, VisibilityOwner}, @@ -13,6 +11,17 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; +// Assist: change_visibility +// +// Adds or changes existing visibility specifier. +// +// ``` +// fn<|> frobnicate() {} +// ``` +// -> +// ``` +// pub(crate) fn frobnicate() {} +// ``` pub(crate) fn change_visibility(ctx: AssistCtx) -> Option { if let Some(vis) = ctx.node_at_offset::() { return change_vis(ctx, vis); diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index e3f30b5defce..13b98d033359 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -7,6 +7,30 @@ use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; use crate::{Assist, AssistCtx, AssistId}; +// Assist: fill_match_arms +// +// Adds missing clauses to a `match` expression. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// <|> +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move{ distance } => (), +// Action::Stop => (), +// } +// } +// ``` pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option { let match_expr = ctx.node_at_offset::()?; let match_arm_list = match_expr.match_arm_list()?; diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 76d86b93dadf..2f36c3baa31e 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -141,6 +141,19 @@ fn main() { ) } +#[test] +fn doctest_change_visibility() { + check( + "change_visibility", + r#####" +fn<|> frobnicate() {} +"#####, + r#####" +pub(crate) fn frobnicate() {} +"#####, + ) +} + #[test] fn doctest_convert_to_guarded_return() { check( @@ -164,3 +177,29 @@ fn main() { "#####, ) } + +#[test] +fn doctest_fill_match_arms() { + check( + "fill_match_arms", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + <|> + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move{ distance } => (), + Action::Stop => (), + } +} +"#####, + ) +} diff --git a/docs/user/assists.md b/docs/user/assists.md index eeb486832178..7a64c80ad599 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -137,6 +137,18 @@ fn main() { } ``` +## `change_visibility` + +Adds or changes existing visibility specifier. + +```rust +// BEFORE +fn<|> frobnicate() {} + +// AFTER +pub(crate) fn frobnicate() {} +``` + ## `convert_to_guarded_return` Replace a large conditional with a guarded return. @@ -159,3 +171,28 @@ fn main() { bar(); } ``` + +## `fill_match_arms` + +Adds missing clauses to a `match` expression. + +```rust +// BEFORE +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + <|> + } +} + +// AFTER +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move{ distance } => (), + Action::Stop => (), + } +} +``` diff --git a/docs/user/features.md b/docs/user/features.md index acf092cec1bb..39dab710dd26 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -118,57 +118,6 @@ impl Debug<|> for Foo { } ``` -- Change Visibility - -```rust -// before: -<|>fn foo() {} - -// after: -<|>pub(crate) fn foo() {} - -// after: -<|>pub fn foo() {} -``` - -- Fill match arms - -```rust -// before: -enum A { - As, - Bs, - Cs(String), - Ds(String, String), - Es{x: usize, y: usize} -} - -fn main() { - let a = A::As; - match a<|> {} -} - -// after: -enum A { - As, - Bs, - Cs(String), - Ds(String, String), - Es{x: usize, y: usize} -} - -fn main() { - let a = A::As; - match <|>a { - A::As => (), - A::Bs => (), - A::Cs(_) => (), - A::Ds(_, _) => (), - A::Es{x, y} => (), - } -} -``` - - Fill struct fields ```rust From 4ef9b8d17a75d3f68951f506ad390e1367c1b2ad Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 18:03:55 +0300 Subject: [PATCH 020/102] use correct spacing for enum pattern --- crates/ra_assists/src/assists/fill_match_arms.rs | 6 +++--- crates/ra_assists/src/doc_tests/generated.rs | 2 +- crates/ra_syntax/src/ast/make.rs | 2 +- docs/user/assists.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 13b98d033359..b6166f947de6 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -26,7 +26,7 @@ use crate::{Assist, AssistCtx, AssistId}; // // fn handle(action: Action) { // match action { -// Action::Move{ distance } => (), +// Action::Move { distance } => (), // Action::Stop => (), // } // } @@ -154,7 +154,7 @@ mod tests { A::Bs => (), A::Cs(_) => (), A::Ds(_, _) => (), - A::Es{ x, y } => (), + A::Es { x, y } => (), } } "#, @@ -207,7 +207,7 @@ mod tests { fn foo(a: &mut A) { match <|>a { - A::Es{ x, y } => (), + A::Es { x, y } => (), } } "#, diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 2f36c3baa31e..43fa159d7df7 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -196,7 +196,7 @@ enum Action { Move { distance: u32 }, Stop } fn handle(action: Action) { match action { - Action::Move{ distance } => (), + Action::Move { distance } => (), Action::Stop => (), } } diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 00422ea913ac..76dad91557d7 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -77,7 +77,7 @@ pub fn tuple_struct_pat( pub fn record_pat(path: ast::Path, pats: impl Iterator) -> ast::RecordPat { let pats_str = pats.map(|p| p.syntax().to_string()).join(", "); - return from_text(&format!("{}{{ {} }}", path.syntax(), pats_str)); + return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str)); fn from_text(text: &str) -> ast::RecordPat { ast_from_text(&format!("fn f({}: ())", text)) diff --git a/docs/user/assists.md b/docs/user/assists.md index 7a64c80ad599..603b29c66142 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -191,7 +191,7 @@ enum Action { Move { distance: u32 }, Stop } fn handle(action: Action) { match action { - Action::Move{ distance } => (), + Action::Move { distance } => (), Action::Stop => (), } } From a5cbd8d5e8aca0d0d8dde175ba13bfa995a753c0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 19:08:13 +0300 Subject: [PATCH 021/102] check style for assist docs --- .../src/assists/add_explicit_type.rs | 2 +- crates/ra_assists/src/assists/add_impl.rs | 2 +- .../src/assists/add_missing_impl_members.rs | 6 +- crates/ra_assists/src/assists/early_return.rs | 2 + crates/ra_assists/src/assists/flip_binexpr.rs | 18 +++++- crates/ra_assists/src/assists/flip_comma.rs | 17 +++++- .../src/assists/inline_local_variable.rs | 18 +++++- crates/ra_assists/src/doc_tests/generated.rs | 52 +++++++++++++++++ docs/user/assists.md | 57 +++++++++++++++++-- xtask/src/codegen/gen_assists_docs.rs | 6 ++ 10 files changed, 165 insertions(+), 15 deletions(-) diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 302b95579083..2903c178193a 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -8,7 +8,7 @@ use crate::{Assist, AssistCtx, AssistId}; // Assist: add_explicit_type // -// Specify type for a let binding +// Specify type for a let binding. // // ``` // fn main() { diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 43aeac7bd6e7..142777b0674f 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -10,7 +10,7 @@ use crate::{Assist, AssistCtx, AssistId}; // Assist: add_impl // -// Adds a new inherent impl for a type +// Adds a new inherent impl for a type. // // ``` // struct Ctx { diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index fe1f2e72e7f5..4ee4d47faca7 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -14,7 +14,7 @@ enum AddMissingImplMembersMode { // Assist: add_impl_missing_members // -// Adds scaffold for required impl members +// Adds scaffold for required impl members. // // ``` // trait T { @@ -50,7 +50,9 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx) -> Opti } // Assist: add_impl_default_members -// Adds scaffold for overriding default impl members +// +// Adds scaffold for overriding default impl members. +// // ``` // trait T { // Type X; diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index b3d0253406c7..48782db4221c 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -14,7 +14,9 @@ use crate::{ }; // Assist: convert_to_guarded_return +// // Replace a large conditional with a guarded return. +// // ``` // fn main() { // <|>if cond { diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index c51035282309..3a1e5cbe1b10 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs @@ -1,11 +1,23 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::ast::{AstNode, BinExpr, BinOp}; use crate::{Assist, AssistCtx, AssistId}; -/// Flip binary expression assist. +// Assist: flip_binexpr +// +// Flips operands of a binary expression. +// +// ``` +// fn main() { +// let _ = 90 +<|> 2; +// } +// ``` +// -> +// ``` +// fn main() { +// let _ = 2 + 90; +// } +// ``` pub(crate) fn flip_binexpr(mut ctx: AssistCtx) -> Option { let expr = ctx.node_at_offset::()?; let lhs = expr.lhs()?.syntax().clone(); diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs index e31cc5e7d70f..d06c5a0e18b3 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/assists/flip_comma.rs @@ -1,10 +1,23 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{algo::non_trivia_sibling, Direction, T}; use crate::{Assist, AssistCtx, AssistId}; +// Assist: flip_comma +// +// Flips two comma-separated items. +// +// ``` +// fn main() { +// ((1, 2),<|> (3, 4)); +// } +// ``` +// -> +// ``` +// fn main() { +// ((3, 4), (1, 2)); +// } +// ``` pub(crate) fn flip_comma(mut ctx: AssistCtx) -> Option { let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index 9bd64decc9db..1997781dbbcc 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ ast::{self, AstNode, AstToken}, @@ -9,6 +7,22 @@ use ra_syntax::{ use crate::assist_ctx::AssistBuilder; use crate::{Assist, AssistCtx, AssistId}; +// Assist: inline_local_variable +// +// Inlines local variable. +// +// ``` +// fn main() { +// let x<|> = 1 + 2; +// x * 4; +// } +// ``` +// -> +// ``` +// fn main() { +// (1 + 2) * 4; +// } +// ``` pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx) -> Option { let let_stmt = ctx.node_at_offset::()?; let bind_pat = match let_stmt.pat()? { diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 43fa159d7df7..d390db33cfe9 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -203,3 +203,55 @@ fn handle(action: Action) { "#####, ) } + +#[test] +fn doctest_flip_binexpr() { + check( + "flip_binexpr", + r#####" +fn main() { + let _ = 90 +<|> 2; +} +"#####, + r#####" +fn main() { + let _ = 2 + 90; +} +"#####, + ) +} + +#[test] +fn doctest_flip_comma() { + check( + "flip_comma", + r#####" +fn main() { + ((1, 2),<|> (3, 4)); +} +"#####, + r#####" +fn main() { + ((3, 4), (1, 2)); +} +"#####, + ) +} + +#[test] +fn doctest_inline_local_variable() { + check( + "inline_local_variable", + r#####" +fn main() { + let x<|> = 1 + 2; + x * 4; +} +"#####, + r#####" +fn main() { + (1 + 2) * 4; +} +"#####, + ) +} diff --git a/docs/user/assists.md b/docs/user/assists.md index 603b29c66142..8e2e8cc94578 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -21,7 +21,7 @@ struct Point { ## `add_explicit_type` -Specify type for a let binding +Specify type for a let binding. ```rust // BEFORE @@ -37,7 +37,7 @@ fn main() { ## `add_impl` -Adds a new inherent impl for a type +Adds a new inherent impl for a type. ```rust // BEFORE @@ -57,7 +57,7 @@ impl Ctx { ## `add_impl_default_members` -Adds scaffold for overriding default impl members +Adds scaffold for overriding default impl members. ```rust // BEFORE @@ -90,7 +90,7 @@ impl T for () { ## `add_impl_missing_members` -Adds scaffold for required impl members +Adds scaffold for required impl members. ```rust // BEFORE @@ -196,3 +196,52 @@ fn handle(action: Action) { } } ``` + +## `flip_binexpr` + +Flips operands of a binary expression. + +```rust +// BEFORE +fn main() { + let _ = 90 +<|> 2; +} + +// AFTER +fn main() { + let _ = 2 + 90; +} +``` + +## `flip_comma` + +Flips two comma-separated items. + +```rust +// BEFORE +fn main() { + ((1, 2),<|> (3, 4)); +} + +// AFTER +fn main() { + ((3, 4), (1, 2)); +} +``` + +## `inline_local_variable` + +Inlines local variable. + +```rust +// BEFORE +fn main() { + let x<|> = 1 + 2; + x * 4; +} + +// AFTER +fn main() { + (1 + 2) * 4; +} +``` diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 2ca7cda63dbe..8dca2ed06e34 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -52,6 +52,12 @@ fn collect_assists() -> Result> { ); let doc = take_until(lines.by_ref(), "```").trim().to_string(); + assert!( + doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with("."), + "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n", + id, doc, + ); + let before = take_until(lines.by_ref(), "```"); assert_eq!(lines.next().unwrap().as_str(), "->"); From 431e4ff4ef83455adc7e2c0e3f732d6dc482641e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 20:07:24 +0300 Subject: [PATCH 022/102] avoid TextEditorBuilder for simple edits --- .../src/completion/complete_postfix.rs | 6 ++--- .../src/completion/completion_item.rs | 12 ++++------ crates/ra_ide_api/src/diagnostics.rs | 9 +++---- crates/ra_ide_api/src/references/rename.rs | 24 +++++++------------ crates/ra_ide_api/src/typing.rs | 7 +++--- 5 files changed, 21 insertions(+), 37 deletions(-) diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs index 555cecb73a58..60ed3518b89a 100644 --- a/crates/ra_ide_api/src/completion/complete_postfix.rs +++ b/crates/ra_ide_api/src/completion/complete_postfix.rs @@ -9,16 +9,14 @@ use crate::{ }; use hir::{Ty, TypeCtor}; use ra_syntax::{ast::AstNode, TextRange, TextUnit}; -use ra_text_edit::TextEditBuilder; +use ra_text_edit::TextEdit; fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { let edit = { let receiver_range = ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range(); let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); - let mut builder = TextEditBuilder::default(); - builder.replace(delete_range, snippet.to_string()); - builder.finish() + TextEdit::replace(delete_range, snippet.to_string()) }; CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) .detail(detail) diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 3e6933bc1cdc..5c9c44704b3b 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -4,7 +4,7 @@ use std::fmt; use hir::Documentation; use ra_syntax::TextRange; -use ra_text_edit::{TextEdit, TextEditBuilder}; +use ra_text_edit::TextEdit; /// `CompletionItem` describes a single completion variant in the editor pop-up. /// It is basically a POD with various properties. To construct a @@ -192,12 +192,10 @@ impl Builder { let label = self.label; let text_edit = match self.text_edit { Some(it) => it, - None => { - let mut builder = TextEditBuilder::default(); - builder - .replace(self.source_range, self.insert_text.unwrap_or_else(|| label.clone())); - builder.finish() - } + None => TextEdit::replace( + self.source_range, + self.insert_text.unwrap_or_else(|| label.clone()), + ), }; CompletionItem { diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs index 8743a3a79831..1f1f5cd742c9 100644 --- a/crates/ra_ide_api/src/diagnostics.rs +++ b/crates/ra_ide_api/src/diagnostics.rs @@ -85,10 +85,9 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec }) .on::(|d| { let node = d.ast(db); - let mut builder = TextEditBuilder::default(); let replacement = format!("Ok({})", node.syntax()); - builder.replace(node.syntax().text_range(), replacement); - let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, builder.finish()); + let edit = TextEdit::replace(node.syntax().text_range(), replacement); + let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); res.borrow_mut().push(Diagnostic { range: d.highlight_range(), message: d.message(), @@ -152,9 +151,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); let end = use_tree_list_node.text_range().end(); let range = TextRange::from_to(start, end); - let mut edit_builder = TextEditBuilder::default(); - edit_builder.delete(range); - return Some(edit_builder.finish()); + return Some(TextEdit::delete(range)); } None } diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs index ee6e73e1bfdf..a8783d7a0dc4 100644 --- a/crates/ra_ide_api/src/references/rename.rs +++ b/crates/ra_ide_api/src/references/rename.rs @@ -3,6 +3,7 @@ use hir::ModuleSource; use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; +use ra_text_edit::TextEdit; use relative_path::{RelativePath, RelativePathBuf}; use crate::{ @@ -43,14 +44,7 @@ fn source_edit_from_file_id_range( range: TextRange, new_name: &str, ) -> SourceFileEdit { - SourceFileEdit { - file_id, - edit: { - let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(range, new_name.into()); - builder.finish() - }, - } + SourceFileEdit { file_id, edit: TextEdit::replace(range, new_name.into()) } } fn rename_mod( @@ -94,11 +88,7 @@ fn rename_mod( let edit = SourceFileEdit { file_id: position.file_id, - edit: { - let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(ast_name.syntax().text_range(), new_name.into()); - builder.finish() - }, + edit: TextEdit::replace(ast_name.syntax().text_range(), new_name.into()), }; source_file_edits.push(edit); @@ -126,12 +116,14 @@ fn rename_reference( #[cfg(test)] mod tests { + use insta::assert_debug_snapshot; + use ra_text_edit::TextEditBuilder; + use test_utils::assert_eq_text; + use crate::{ mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, ReferenceSearchResult, }; - use insta::assert_debug_snapshot; - use test_utils::assert_eq_text; #[test] fn test_find_all_refs_for_local() { @@ -452,7 +444,7 @@ mod tests { fn test_rename(text: &str, new_name: &str, expected: &str) { let (analysis, position) = single_file_with_position(text); let source_change = analysis.rename(position, new_name).unwrap(); - let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); + let mut text_edit_builder = TextEditBuilder::default(); let mut file_id: Option = None; if let Some(change) = source_change { for edit in change.info.source_file_edits { diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 26a3111fd80d..2dfbe6944dd9 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -22,7 +22,7 @@ use ra_syntax::{ SyntaxKind::*, SyntaxToken, TextRange, TextUnit, TokenAtOffset, }; -use ra_text_edit::{TextEdit, TextEditBuilder}; +use ra_text_edit::TextEdit; use crate::{db::RootDatabase, source_change::SingleFileChange, SourceChange, SourceFileEdit}; @@ -49,13 +49,12 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option Date: Sat, 26 Oct 2019 19:58:18 +0300 Subject: [PATCH 023/102] support range selection in assist docs --- .../src/assists/introduce_variable.rs | 18 ++++++++-- crates/ra_assists/src/doc_tests.rs | 7 ++-- crates/ra_assists/src/doc_tests/generated.rs | 18 ++++++++++ crates/test_utils/src/lib.rs | 34 +++++++++++++++++-- docs/user/assists.md | 17 ++++++++++ 5 files changed, 85 insertions(+), 9 deletions(-) diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs index 43378c4b05ea..8245dc99f57e 100644 --- a/crates/ra_assists/src/assists/introduce_variable.rs +++ b/crates/ra_assists/src/assists/introduce_variable.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use format_buf::format; use hir::db::HirDatabase; use ra_syntax::{ @@ -14,6 +12,22 @@ use test_utils::tested_by; use crate::{Assist, AssistCtx, AssistId}; +// Assist: introduce_variable +// +// Extracts subexpression into a variable. +// +// ``` +// fn main() { +// <|>(1 + 2)<|> * 4; +// } +// ``` +// -> +// ``` +// fn main() { +// let var_name = (1 + 2); +// var_name * 4; +// } +// ``` pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option { if ctx.frange.range.is_empty() { return None; diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 872bbdf17a5b..0ccf9d7308e8 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs @@ -7,13 +7,12 @@ mod generated; use hir::mock::MockDatabase; use ra_db::FileRange; -use ra_syntax::TextRange; -use test_utils::{assert_eq_text, extract_offset}; +use test_utils::{assert_eq_text, extract_range_or_offset}; fn check(assist_id: &str, before: &str, after: &str) { - let (before_cursor_pos, before) = extract_offset(before); + let (selection, before) = extract_range_or_offset(before); let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); - let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; + let frange = FileRange { file_id, range: selection.into() }; let (_assist_id, action) = crate::assists(&db, frange) .into_iter() diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index d390db33cfe9..493bd94d0319 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -255,3 +255,21 @@ fn main() { "#####, ) } + +#[test] +fn doctest_introduce_variable() { + check( + "introduce_variable", + r#####" +fn main() { + <|>(1 + 2)<|> * 4; +} +"#####, + r#####" +fn main() { + let var_name = (1 + 2); + var_name * 4; +} +"#####, + ) +} diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index c40943b63c57..1244ea8cf189 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -1,4 +1,10 @@ -//! FIXME: write short doc here +//! Assorted testing utilities. +//! +//! Most notable things are: +//! +//! * Rich text comparison, which outputs a diff. +//! * Extracting markup (mainly, `<|>` markers) out of fixture strings. +//! * marks (see the eponymous module). #[macro_use] pub mod marks; @@ -43,7 +49,7 @@ pub fn extract_offset(text: &str) -> (TextUnit, String) { } } -pub fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> { +fn try_extract_offset(text: &str) -> Option<(TextUnit, String)> { let cursor_pos = text.find(CURSOR_MARKER)?; let mut new_text = String::with_capacity(text.len() - CURSOR_MARKER.len()); new_text.push_str(&text[..cursor_pos]); @@ -59,12 +65,34 @@ pub fn extract_range(text: &str) -> (TextRange, String) { } } -pub fn try_extract_range(text: &str) -> Option<(TextRange, String)> { +fn try_extract_range(text: &str) -> Option<(TextRange, String)> { let (start, text) = try_extract_offset(text)?; let (end, text) = try_extract_offset(&text)?; Some((TextRange::from_to(start, end), text)) } +pub enum RangeOrOffset { + Range(TextRange), + Offset(TextUnit), +} + +impl From for TextRange { + fn from(selection: RangeOrOffset) -> Self { + match selection { + RangeOrOffset::Range(it) => it, + RangeOrOffset::Offset(it) => TextRange::from_to(it, it), + } + } +} + +pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) { + if let Some((range, text)) = try_extract_range(text) { + return (RangeOrOffset::Range(range), text); + } + let (offset, text) = extract_offset(text); + (RangeOrOffset::Offset(offset), text) +} + /// Extracts ranges, marked with ` ` paris from the `text` pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec, String) { let open = format!("<{}>", tag); diff --git a/docs/user/assists.md b/docs/user/assists.md index 8e2e8cc94578..182f07e982da 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -245,3 +245,20 @@ fn main() { (1 + 2) * 4; } ``` + +## `introduce_variable` + +Extracts subexpression into a variable. + +```rust +// BEFORE +fn main() { + <|>(1 + 2)<|> * 4; +} + +// AFTER +fn main() { + let var_name = (1 + 2); + var_name * 4; +} +``` From cf4720ffd5524f1ddda411e4810da8d97a0c593f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 26 Oct 2019 21:17:39 +0300 Subject: [PATCH 024/102] use unicode bar for drawing the cursor --- .../src/assists/change_visibility.rs | 2 +- crates/ra_assists/src/doc_tests/generated.rs | 2 +- docs/user/assists.md | 29 ++++++++++--------- xtask/src/codegen/gen_assists_docs.rs | 8 +++-- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index 88118cdf7c04..bed3436778d7 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs @@ -16,7 +16,7 @@ use crate::{Assist, AssistCtx, AssistId}; // Adds or changes existing visibility specifier. // // ``` -// fn<|> frobnicate() {} +// <|>fn frobnicate() {} // ``` // -> // ``` diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 493bd94d0319..b96d5772e09b 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -146,7 +146,7 @@ fn doctest_change_visibility() { check( "change_visibility", r#####" -fn<|> frobnicate() {} +<|>fn frobnicate() {} "#####, r#####" pub(crate) fn frobnicate() {} diff --git a/docs/user/assists.md b/docs/user/assists.md index 182f07e982da..ee1cfa142dee 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -1,5 +1,8 @@ # Assists +Cursor position or selection is signified by `┃` character. + + ## `add_derive` Adds a new `#[derive()]` clause to a struct or enum. @@ -8,7 +11,7 @@ Adds a new `#[derive()]` clause to a struct or enum. // BEFORE struct Point { x: u32, - y: u32,<|> + y: u32,┃ } // AFTER @@ -26,7 +29,7 @@ Specify type for a let binding. ```rust // BEFORE fn main() { - let x<|> = 92; + let x┃ = 92; } // AFTER @@ -42,7 +45,7 @@ Adds a new inherent impl for a type. ```rust // BEFORE struct Ctx { - data: T,<|> + data: T,┃ } // AFTER @@ -69,7 +72,7 @@ trait T { impl T for () { Type X = (); - fn foo(&self) {}<|> + fn foo(&self) {}┃ } @@ -100,7 +103,7 @@ trait T { fn bar(&self) {} } -impl T for () {<|> +impl T for () {┃ } @@ -128,7 +131,7 @@ This means something of the form `!x` or `x != y`. ```rust // BEFORE fn main() { - if x != 4 ||<|> !y {} + if x != 4 ||┃ !y {} } // AFTER @@ -143,7 +146,7 @@ Adds or changes existing visibility specifier. ```rust // BEFORE -fn<|> frobnicate() {} +┃fn frobnicate() {} // AFTER pub(crate) fn frobnicate() {} @@ -156,7 +159,7 @@ Replace a large conditional with a guarded return. ```rust // BEFORE fn main() { - <|>if cond { + ┃if cond { foo(); bar(); } @@ -182,7 +185,7 @@ enum Action { Move { distance: u32 }, Stop } fn handle(action: Action) { match action { - <|> + ┃ } } @@ -204,7 +207,7 @@ Flips operands of a binary expression. ```rust // BEFORE fn main() { - let _ = 90 +<|> 2; + let _ = 90 +┃ 2; } // AFTER @@ -220,7 +223,7 @@ Flips two comma-separated items. ```rust // BEFORE fn main() { - ((1, 2),<|> (3, 4)); + ((1, 2),┃ (3, 4)); } // AFTER @@ -236,7 +239,7 @@ Inlines local variable. ```rust // BEFORE fn main() { - let x<|> = 1 + 2; + let x┃ = 1 + 2; x * 4; } @@ -253,7 +256,7 @@ Extracts subexpression into a variable. ```rust // BEFORE fn main() { - <|>(1 + 2)<|> * 4; + ┃(1 + 2)┃ * 4; } // AFTER diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 8dca2ed06e34..0c4cf21529da 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -107,9 +107,13 @@ r#####" } fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { - let mut buf = String::from("# Assists\n"); + let mut buf = String::from( + "# Assists\n\nCursor position or selection is signified by `┃` character.\n\n", + ); for assist in assists { + let before = assist.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar + let after = assist.after.replace("<|>", "┃"); let docs = format!( " ## `{}` @@ -124,7 +128,7 @@ fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> { {} ``` ", - assist.id, assist.doc, assist.before, assist.after + assist.id, assist.doc, before, after ); buf.push_str(&docs); } From a490ba06fa635ecb34b5ce0b7205621eefaee603 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 11:26:46 +0300 Subject: [PATCH 025/102] document some more assists --- .../src/assists/merge_match_arms.rs | 26 ++++- crates/ra_assists/src/assists/move_bounds.rs | 17 +++- crates/ra_assists/src/assists/move_guard.rs | 52 +++++++++- crates/ra_assists/src/doc_tests/generated.rs | 97 +++++++++++++++++++ docs/user/assists.md | 93 ++++++++++++++++++ docs/user/features.md | 84 ---------------- 6 files changed, 279 insertions(+), 90 deletions(-) diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index 17baa98f9272..f5ddd7159440 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs @@ -1,9 +1,31 @@ -//! FIXME: write short doc here - use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; use hir::db::HirDatabase; use ra_syntax::ast::{AstNode, MatchArm}; +// Assist: merge_match_arms +// +// Merges identical match arms. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// <|>Action::Move(..) => foo(), +// Action::Stop => foo(), +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move(..) | Action::Stop => foo(), +// } +// } +// ``` pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option { let current_arm = ctx.node_at_offset::()?; diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs index d2444b6b9c6a..f96e19a9f093 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/assists/move_bounds.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner}, @@ -9,6 +7,21 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; +// Assist: move_bounds_to_where_clause +// +// Moves inline type bounds to a where clause. +// +// ``` +// fn applyF: FnOnce(T) -> U>(f: F, x: T) -> U { +// f(x) +// } +// ``` +// -> +// ``` +// fn apply(f: F, x: T) -> U where F: FnOnce(T) -> U { +// f(x) +// } +// ``` pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx) -> Option { let type_param_list = ctx.node_at_offset::()?; diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index 51aea6334080..36c95128d35f 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ ast, @@ -9,6 +7,31 @@ use ra_syntax::{ use crate::{Assist, AssistCtx, AssistId}; +// Assist: move_guard_to_arm_body +// +// Moves match guard into match arm body. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move { distance } <|>if distance > 10 => foo(), +// _ => (), +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move { distance } => if distance > 10 { foo() }, +// _ => (), +// } +// } +// ``` pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Option { let match_arm = ctx.node_at_offset::()?; let guard = match_arm.guard()?; @@ -42,6 +65,31 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op ctx.build() } +// Assist: move_arm_cond_to_match_guard +// +// Moves if expression from match arm body into a guard. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move { distance } => <|>if distance > 10 { foo() }, +// _ => (), +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move { distance } if distance > 10 => foo(), +// _ => (), +// } +// } +// ``` pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) -> Option { let match_arm: MatchArm = ctx.node_at_offset::()?; let last_match_pat = match_arm.pats().last()?; diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index b96d5772e09b..09677af68ffd 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -273,3 +273,100 @@ fn main() { "#####, ) } + +#[test] +fn doctest_merge_match_arms() { + check( + "merge_match_arms", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + <|>Action::Move(..) => foo(), + Action::Stop => foo(), + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) | Action::Stop => foo(), + } +} +"#####, + ) +} + +#[test] +fn doctest_move_arm_cond_to_match_guard() { + check( + "move_arm_cond_to_match_guard", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => <|>if distance > 10 { foo() }, + _ => (), + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } if distance > 10 => foo(), + _ => (), + } +} +"#####, + ) +} + +#[test] +fn doctest_move_bounds_to_where_clause() { + check( + "move_bounds_to_where_clause", + r#####" +fn applyF: FnOnce(T) -> U>(f: F, x: T) -> U { + f(x) +} +"#####, + r#####" +fn apply(f: F, x: T) -> U where F: FnOnce(T) -> U { + f(x) +} +"#####, + ) +} + +#[test] +fn doctest_move_guard_to_arm_body() { + check( + "move_guard_to_arm_body", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } <|>if distance > 10 => foo(), + _ => (), + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => if distance > 10 { foo() }, + _ => (), + } +} +"#####, + ) +} diff --git a/docs/user/assists.md b/docs/user/assists.md index ee1cfa142dee..34a95696cae2 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -265,3 +265,96 @@ fn main() { var_name * 4; } ``` + +## `merge_match_arms` + +Merges identical match arms. + +```rust +// BEFORE +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + ┃Action::Move(..) => foo(), + Action::Stop => foo(), + } +} + +// AFTER +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) | Action::Stop => foo(), + } +} +``` + +## `move_arm_cond_to_match_guard` + +Moves if expression from match arm body into a guard. + +```rust +// BEFORE +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => ┃if distance > 10 { foo() }, + _ => (), + } +} + +// AFTER +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } if distance > 10 => foo(), + _ => (), + } +} +``` + +## `move_bounds_to_where_clause` + +Moves inline type bounds to a where clause. + +```rust +// BEFORE +fn apply U>(f: F, x: T) -> U { + f(x) +} + +// AFTER +fn apply(f: F, x: T) -> U where F: FnOnce(T) -> U { + f(x) +} +``` + +## `move_guard_to_arm_body` + +Moves match guard into match arm body. + +```rust +// BEFORE +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } ┃if distance > 10 => foo(), + _ => (), + } +} + +// AFTER +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => if distance > 10 { foo() }, + _ => (), + } +} +``` diff --git a/docs/user/features.md b/docs/user/features.md index 39dab710dd26..2e213e34c380 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -154,45 +154,6 @@ fn main() { } ``` -- Flip `,` - -```rust -// before: -fn foo(x: usize,<|> dim: (usize, usize)) {} -// after: -fn foo(dim: (usize, usize), x: usize) {} -``` - -- Introduce variable: - -```rust -// before: -fn foo() { - foo(<|>1 + 1<|>); -} - -// after: -fn foo() { - let var_name = 1 + 1; - foo(var_name); -} -``` - -- Inline local variable: - -```rust -// before: -fn foo() { - let a<|> = 1 + 1; - let b = a * 10; -} - -// after: -fn foo() { - let b = (1 + 1) * 10; -} -``` - - Remove `dbg!` ```rust @@ -245,41 +206,6 @@ use crate:<|>:db::{RootDatabase, FileSymbol}; use crate::{<|>db::{RootDatabase, FileSymbol}}; ``` -- Flip binary expression - -```rust -// before: -fn foo() { - if 1 <<|> 2 { - println!("Who would have thought?"); - } -} -// after: -fn foo() { - if 2 ><|> 1 { - println!("Who would have thought?"); - } -} -``` - -- Move guard expression to match arm body -```rust -// before: -fn f() { - match x { - <|>y @ 4 | y @ 5 if y > 5 => true, - _ => false - } -} -// after: -fn f() { - match x { - y @ 4 | y @ 5 => if y > 5 { <|>true }, - _ => false - } -} -``` - - Move if condition to match arm guard ```rust // before: @@ -309,16 +235,6 @@ fn f() { } ``` -- Move type bounds to where clause - -```rust -// before: -fn foo T>() {} - -// after: -fn foo() where T: u32, F: FnOnce(T) -> T {} -``` - - Make raw string unescaped ```rust From 384032442965b70001d7c15ec0db65bfe5634ee9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 11:32:39 +0300 Subject: [PATCH 026/102] raw string assists work in macros --- crates/ra_assists/src/assists/raw_string.rs | 145 +++++++++++--------- 1 file changed, 77 insertions(+), 68 deletions(-) diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 2d2e31e5134d..9c996c9028c4 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -1,17 +1,19 @@ //! FIXME: write short doc here use hir::db::HirDatabase; -use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; +use ra_syntax::{ + SyntaxKind::{RAW_STRING, STRING}, + SyntaxToken, TextRange, TextUnit, +}; use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::STRING { + let token = ctx.token_at_offset().right_biased()?; + if token.kind() != STRING { return None; } - let token = literal.token(); let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; let start_of_inside = usual_string_range.start().to_usize() + 1; @@ -30,20 +32,69 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option) -> Option { + let token = raw_string_token(&ctx)?; + let text = token.text().as_str(); + let usual_string_range = find_usual_string_range(text)?; + ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { + edit.target(token.text_range()); + // parse inside string to escape `"` + let start_of_inside = usual_string_range.start().to_usize() + 1; + let end_of_inside = usual_string_range.end().to_usize(); + let inside_str = &text[start_of_inside..end_of_inside]; + let escaped = inside_str.escape_default().to_string(); + edit.replace(token.text_range(), format!("\"{}\"", escaped)); + }); + ctx.build() +} + +pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { + let token = raw_string_token(&ctx)?; + ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { + edit.target(token.text_range()); + edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); + edit.insert(token.text_range().end(), "#"); + }); + ctx.build() +} + +pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { + let token = raw_string_token(&ctx)?; + let text = token.text().as_str(); + if text.starts_with("r\"") { + // no hash to remove + return None; + } + ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { + edit.target(token.text_range()); + let result = &text[2..text.len() - 1]; + let result = if result.starts_with("\"") { + // no more hash, escape + let internal_str = &result[1..result.len() - 1]; + format!("\"{}\"", internal_str.escape_default().to_string()) + } else { + result.to_owned() + }; + edit.replace(token.text_range(), format!("r{}", result)); + }); + ctx.build() +} + +fn raw_string_token(ctx: &AssistCtx) -> Option { + ctx.token_at_offset().right_biased().filter(|it| it.kind() == RAW_STRING) +} + fn count_hashes(s: &str) -> usize { let mut max_hash_streak = 0usize; for idx in s.match_indices("\"#").map(|(i, _)| i) { @@ -63,65 +114,6 @@ fn find_usual_string_range(s: &str) -> Option { )) } -pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - let token = literal.token(); - let text = token.text().as_str(); - let usual_string_range = find_usual_string_range(text)?; - ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { - edit.target(literal.syntax().text_range()); - // parse inside string to escape `"` - let start_of_inside = usual_string_range.start().to_usize() + 1; - let end_of_inside = usual_string_range.end().to_usize(); - let inside_str = &text[start_of_inside..end_of_inside]; - let escaped = inside_str.escape_default().to_string(); - edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); - }); - ctx.build() -} - -pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { - edit.target(literal.syntax().text_range()); - edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); - edit.insert(literal.syntax().text_range().end(), "#"); - }); - ctx.build() -} - -pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { - let literal = ctx.node_at_offset::()?; - if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { - return None; - } - let token = literal.token(); - let text = token.text().as_str(); - if text.starts_with("r\"") { - // no hash to remove - return None; - } - ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { - edit.target(literal.syntax().text_range()); - let result = &text[2..text.len() - 1]; - let result = if result.starts_with("\"") { - // no more hash, escape - let internal_str = &result[1..result.len() - 1]; - format!("\"{}\"", internal_str.escape_default().to_string()) - } else { - result.to_owned() - }; - edit.replace(literal.syntax().text_range(), format!("r{}", result)); - }); - ctx.build() -} - #[cfg(test)] mod test { use super::*; @@ -158,6 +150,23 @@ string"#; ) } + #[test] + fn make_raw_string_works_inside_macros() { + check_assist( + make_raw_string, + r#" + fn f() { + format!(<|>"x = {}", 92) + } + "#, + r##" + fn f() { + format!(<|>r#"x = {}"#, 92) + } + "##, + ) + } + #[test] fn make_raw_string_hashes_inside_works() { check_assist( From 61349a3d18353ddfbd992a3bf51a88f5f0cfcddd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 11:45:59 +0300 Subject: [PATCH 027/102] extract assist helper for getting a specific token --- crates/ra_assists/src/assist_ctx.rs | 6 +++++- crates/ra_assists/src/assists/flip_comma.rs | 2 +- crates/ra_assists/src/assists/raw_string.rs | 17 +++++------------ crates/ra_assists/src/assists/split_import.rs | 2 +- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index e270c5d60da3..20d33fb164a1 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -5,7 +5,7 @@ use ra_db::FileRange; use ra_fmt::{leading_indent, reindent}; use ra_syntax::{ algo::{self, find_covering_element, find_node_at_offset}, - AstNode, SourceFile, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit, + AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit, TokenAtOffset, }; use ra_text_edit::TextEditBuilder; @@ -111,6 +111,10 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { self.source_file.syntax().token_at_offset(self.frange.range.start()) } + pub(crate) fn find_token_at_offset(&self, kind: SyntaxKind) -> Option { + self.token_at_offset().find(|it| it.kind() == kind) + } + pub(crate) fn node_at_offset(&self) -> Option { find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) } diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs index d06c5a0e18b3..53ba8011d756 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/assists/flip_comma.rs @@ -19,7 +19,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn flip_comma(mut ctx: AssistCtx) -> Option { - let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?; + let comma = ctx.find_token_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 9c996c9028c4..ea756d1cabd4 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -3,17 +3,14 @@ use hir::db::HirDatabase; use ra_syntax::{ SyntaxKind::{RAW_STRING, STRING}, - SyntaxToken, TextRange, TextUnit, + TextRange, TextUnit, }; use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option { - let token = ctx.token_at_offset().right_biased()?; - if token.kind() != STRING { - return None; - } + let token = ctx.find_token_at_offset(STRING)?; let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; let start_of_inside = usual_string_range.start().to_usize() + 1; @@ -44,7 +41,7 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option) -> Option { - let token = raw_string_token(&ctx)?; + let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { @@ -60,7 +57,7 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option< } pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { - let token = raw_string_token(&ctx)?; + let token = ctx.find_token_at_offset(RAW_STRING)?; ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { edit.target(token.text_range()); edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); @@ -70,7 +67,7 @@ pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { } pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { - let token = raw_string_token(&ctx)?; + let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); if text.starts_with("r\"") { // no hash to remove @@ -91,10 +88,6 @@ pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option) -> Option { - ctx.token_at_offset().right_biased().filter(|it| it.kind() == RAW_STRING) -} - fn count_hashes(s: &str) -> usize { let mut max_hash_streak = 0usize; for idx in s.match_indices("\"#").map(|(i, _)| i) { diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index fe3e64af50e0..09bde1b72cf5 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs @@ -8,7 +8,7 @@ use ra_syntax::{ast, AstNode, TextUnit, T}; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn split_import(mut ctx: AssistCtx) -> Option { - let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == T![::])?; + let colon_colon = ctx.find_token_at_offset(T![::])?; let path = ast::Path::cast(colon_colon.parent())?; let top_path = successors(Some(path), |it| it.parent_path()).last()?; From 8118dc1bb9bc63670f72965e5115daa96e8c72fd Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 11:48:40 +0300 Subject: [PATCH 028/102] use more consistent naming I think this is the first time I use global rename for rust-analyzer itself :-) --- crates/ra_assists/src/assist_ctx.rs | 2 +- crates/ra_assists/src/assists/add_derive.rs | 2 +- crates/ra_assists/src/assists/add_explicit_type.rs | 2 +- crates/ra_assists/src/assists/add_impl.rs | 2 +- crates/ra_assists/src/assists/add_missing_impl_members.rs | 2 +- crates/ra_assists/src/assists/apply_demorgan.rs | 2 +- crates/ra_assists/src/assists/auto_import.rs | 2 +- crates/ra_assists/src/assists/change_visibility.rs | 2 +- crates/ra_assists/src/assists/early_return.rs | 2 +- crates/ra_assists/src/assists/fill_match_arms.rs | 2 +- crates/ra_assists/src/assists/flip_binexpr.rs | 2 +- crates/ra_assists/src/assists/inline_local_variable.rs | 2 +- crates/ra_assists/src/assists/merge_match_arms.rs | 2 +- crates/ra_assists/src/assists/move_bounds.rs | 2 +- crates/ra_assists/src/assists/move_guard.rs | 4 ++-- crates/ra_assists/src/assists/remove_dbg.rs | 2 +- crates/ra_assists/src/assists/replace_if_let_with_match.rs | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 20d33fb164a1..5f85f20e24c8 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -115,7 +115,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { self.token_at_offset().find(|it| it.kind() == kind) } - pub(crate) fn node_at_offset(&self) -> Option { + pub(crate) fn find_node_at_offset(&self) -> Option { find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) } pub(crate) fn covering_element(&self) -> SyntaxElement { diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index b077acb8142a..d1e925b71f20 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs @@ -26,7 +26,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option { - let nominal = ctx.node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let node_start = derive_insertion_offset(&nominal)?; ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { let derive_attr = nominal diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 2903c178193a..ffbdc0b6294a 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_explicit_type(mut ctx: AssistCtx) -> Option { - let stmt = ctx.node_at_offset::()?; + let stmt = ctx.find_node_at_offset::()?; let expr = stmt.initializer()?; let pat = stmt.pat()?; // Must be a binding diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 142777b0674f..fd3588d24967 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -28,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { - let nominal = ctx.node_at_offset::()?; + let nominal = ctx.find_node_at_offset::()?; let name = nominal.name()?; ctx.add_action(AssistId("add_impl"), "add impl", |edit| { edit.target(nominal.syntax().text_range()); diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 4ee4d47faca7..2585f3045426 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -96,7 +96,7 @@ fn add_missing_impl_members_inner( assist_id: &'static str, label: &'static str, ) -> Option { - let impl_node = ctx.node_at_offset::()?; + let impl_node = ctx.find_node_at_offset::()?; let impl_item_list = impl_node.item_list()?; let trait_def = { diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 75144cefe2e0..8d5984a583ad 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -24,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn apply_demorgan(mut ctx: AssistCtx) -> Option { - let expr = ctx.node_at_offset::()?; + let expr = ctx.find_node_at_offset::()?; let op = expr.op_kind()?; let op_range = expr.op_token()?.text_range(); let opposite_op = opposite_logic_op(op)?; diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 02c58e7c6de6..a1c2aaa7299a 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs @@ -547,7 +547,7 @@ pub fn auto_import_text_edit( } pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option { - let path: ast::Path = ctx.node_at_offset()?; + let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { return None; diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index bed3436778d7..770ea04fa3a6 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs @@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; // pub(crate) fn frobnicate() {} // ``` pub(crate) fn change_visibility(ctx: AssistCtx) -> Option { - if let Some(vis) = ctx.node_at_offset::() { + if let Some(vis) = ctx.find_node_at_offset::() { return change_vis(ctx, vis); } add_vis(ctx) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 48782db4221c..75822dc65a56 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -36,7 +36,7 @@ use crate::{ // } // ``` pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> Option { - let if_expr: ast::IfExpr = ctx.node_at_offset()?; + let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let expr = if_expr.condition()?.expr()?; let then_block = if_expr.then_branch()?.block()?; if if_expr.else_branch().is_some() { diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index b6166f947de6..c62c0efbefd6 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option { - let match_expr = ctx.node_at_offset::()?; + let match_expr = ctx.find_node_at_offset::()?; let match_arm_list = match_expr.match_arm_list()?; // We already have some match arms, so we don't provide any assists. diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index 3a1e5cbe1b10..9765d5dddc08 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs @@ -19,7 +19,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn flip_binexpr(mut ctx: AssistCtx) -> Option { - let expr = ctx.node_at_offset::()?; + let expr = ctx.find_node_at_offset::()?; let lhs = expr.lhs()?.syntax().clone(); let rhs = expr.rhs()?.syntax().clone(); let op_range = expr.op_token()?.text_range(); diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index 1997781dbbcc..fe8fa2a868dd 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs @@ -24,7 +24,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx) -> Option { - let let_stmt = ctx.node_at_offset::()?; + let let_stmt = ctx.find_node_at_offset::()?; let bind_pat = match let_stmt.pat()? { ast::Pat::BindPat(pat) => pat, _ => return None, diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index f5ddd7159440..b0c4ee78b59e 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs @@ -27,7 +27,7 @@ use ra_syntax::ast::{AstNode, MatchArm}; // } // ``` pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option { - let current_arm = ctx.node_at_offset::()?; + let current_arm = ctx.find_node_at_offset::()?; // We check if the following match arm matches this one. We could, but don't, // compare to the previous match arm as well. diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs index f96e19a9f093..edf2897c6ce2 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/assists/move_bounds.rs @@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx) -> Option { - let type_param_list = ctx.node_at_offset::()?; + let type_param_list = ctx.find_node_at_offset::()?; let mut type_params = type_param_list.type_params(); if type_params.all(|p| p.type_bound_list().is_none()) { diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index 36c95128d35f..e820a73c8d90 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs @@ -33,7 +33,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // ``` pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Option { - let match_arm = ctx.node_at_offset::()?; + let match_arm = ctx.find_node_at_offset::()?; let guard = match_arm.guard()?; let space_before_guard = guard.syntax().prev_sibling_or_token(); @@ -91,7 +91,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op // } // ``` pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) -> Option { - let match_arm: MatchArm = ctx.node_at_offset::()?; + let match_arm: MatchArm = ctx.find_node_at_offset::()?; let last_match_pat = match_arm.pats().last()?; let arm_body = match_arm.expr()?; diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index 1a7e2b3050cb..ac2c43e1adca 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs @@ -8,7 +8,7 @@ use ra_syntax::{ }; pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { - let macro_call = ctx.node_at_offset::()?; + let macro_call = ctx.find_node_at_offset::()?; if !is_valid_macrocall(¯o_call, "dbg")? { return None; diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index 749ff338aa6d..da276e47bf4e 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs @@ -8,7 +8,7 @@ use ra_syntax::{ast, AstNode}; use crate::{Assist, AssistCtx, AssistId}; pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> Option { - let if_expr: ast::IfExpr = ctx.node_at_offset()?; + let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; let pat = cond.pat()?; let expr = cond.expr()?; From 860bbd56ef8e5549c36de34966c1451c89179feb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 12:04:06 +0300 Subject: [PATCH 029/102] lightly document assist_ctx module --- crates/ra_assists/src/assist_ctx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 5f85f20e24c8..c527366791fb 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -1,4 +1,4 @@ -//! FIXME: write short doc here +//! This module defines `AssistCtx` -- the API surface that is exposed to assists. use hir::db::HirDatabase; use ra_db::FileRange; From da5528824a836a4f36f44f90adc9fadcc98ca75b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 12:22:53 +0300 Subject: [PATCH 030/102] document almost all assists --- crates/ra_assists/src/assists/raw_string.rs | 62 ++++++- crates/ra_assists/src/assists/remove_dbg.rs | 20 +- .../src/assists/replace_if_let_with_match.rs | 28 ++- crates/ra_assists/src/assists/split_import.rs | 13 +- crates/ra_assists/src/doc_tests/generated.rs | 126 +++++++++++++ docs/user/assists.md | 119 ++++++++++++ docs/user/features.md | 174 ------------------ 7 files changed, 359 insertions(+), 183 deletions(-) diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index ea756d1cabd4..2df48a8380cb 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::db::HirDatabase; use ra_syntax::{ SyntaxKind::{RAW_STRING, STRING}, @@ -9,6 +7,21 @@ use rustc_lexer; use crate::{Assist, AssistCtx, AssistId}; +// Assist: make_raw_string +// +// Adds `r#` to a plain string literal. +// +// ``` +// fn main() { +// "Hello,<|> World!"; +// } +// ``` +// -> +// ``` +// fn main() { +// r#"Hello, World!"#; +// } +// ``` pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(STRING)?; let text = token.text().as_str(); @@ -40,6 +53,21 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option "World!""#; +// } +// ``` +// -> +// ``` +// fn main() { +// "Hello, \"World!\""; +// } +// ``` pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); @@ -56,6 +84,21 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option< ctx.build() } +// Assist: add_hash +// +// Adds a hash to a raw string literal. +// +// ``` +// fn main() { +// r#"Hello,<|> World!"#; +// } +// ``` +// -> +// ``` +// fn main() { +// r##"Hello, World!"##; +// } +// ``` pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { @@ -66,6 +109,21 @@ pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { ctx.build() } +// Assist: remove_hash +// +// Removes a hash from a raw string literal. +// +// ``` +// fn main() { +// r#"Hello,<|> World!"#; +// } +// ``` +// -> +// ``` +// fn main() { +// r"Hello, World!"; +// } +// ``` pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index ac2c43e1adca..44b8de81452e 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs @@ -1,12 +1,26 @@ -//! FIXME: write short doc here - -use crate::{Assist, AssistCtx, AssistId}; use hir::db::HirDatabase; use ra_syntax::{ ast::{self, AstNode}, TextUnit, T, }; +use crate::{Assist, AssistCtx, AssistId}; + +// Assist: remove_dbg +// +// Removes `dbg!()` macro call. +// +// ``` +// fn main() { +// <|>dbg!(92); +// } +// ``` +// -> +// ``` +// fn main() { +// 92; +// } +// ``` pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { let macro_call = ctx.find_node_at_offset::()?; diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index da276e47bf4e..58ef2ff20673 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use format_buf::format; use hir::db::HirDatabase; use ra_fmt::extract_trivial_expression; @@ -7,6 +5,32 @@ use ra_syntax::{ast, AstNode}; use crate::{Assist, AssistCtx, AssistId}; +// Assist: replace_if_let_with_match +// +// Replaces `if let` with an else branch with a `match` expression. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// <|>if let Action::Move { distance } = action { +// foo(distance) +// } else { +// bar() +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move { distance } => foo(distance), +// _ => bar(), +// } +// } +// ``` pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index 09bde1b72cf5..8d8a2898787f 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use std::iter::successors; use hir::db::HirDatabase; @@ -7,6 +5,17 @@ use ra_syntax::{ast, AstNode, TextUnit, T}; use crate::{Assist, AssistCtx, AssistId}; +// Assist: split_import +// +// Wraps the tail of import into braces. +// +// ``` +// use std::<|>collections::HashMap; +// ``` +// -> +// ``` +// use std::{collections::HashMap}; +// ``` pub(crate) fn split_import(mut ctx: AssistCtx) -> Option { let colon_colon = ctx.find_token_at_offset(T![::])?; let path = ast::Path::cast(colon_colon.parent())?; diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 09677af68ffd..b8d335911ffa 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -39,6 +39,23 @@ fn main() { ) } +#[test] +fn doctest_add_hash() { + check( + "add_hash", + r#####" +fn main() { + r#"Hello,<|> World!"#; +} +"#####, + r#####" +fn main() { + r##"Hello, World!"##; +} +"#####, + ) +} + #[test] fn doctest_add_impl() { check( @@ -274,6 +291,40 @@ fn main() { ) } +#[test] +fn doctest_make_raw_string() { + check( + "make_raw_string", + r#####" +fn main() { + "Hello,<|> World!"; +} +"#####, + r#####" +fn main() { + r#"Hello, World!"#; +} +"#####, + ) +} + +#[test] +fn doctest_make_usual_string() { + check( + "make_usual_string", + r#####" +fn main() { + r#"Hello,<|> "World!""#; +} +"#####, + r#####" +fn main() { + "Hello, \"World!\""; +} +"#####, + ) +} + #[test] fn doctest_merge_match_arms() { check( @@ -370,3 +421,78 @@ fn handle(action: Action) { "#####, ) } + +#[test] +fn doctest_remove_dbg() { + check( + "remove_dbg", + r#####" +fn main() { + <|>dbg!(92); +} +"#####, + r#####" +fn main() { + 92; +} +"#####, + ) +} + +#[test] +fn doctest_remove_hash() { + check( + "remove_hash", + r#####" +fn main() { + r#"Hello,<|> World!"#; +} +"#####, + r#####" +fn main() { + r"Hello, World!"; +} +"#####, + ) +} + +#[test] +fn doctest_replace_if_let_with_match() { + check( + "replace_if_let_with_match", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + <|>if let Action::Move { distance } = action { + foo(distance) + } else { + bar() + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => foo(distance), + _ => bar(), + } +} +"#####, + ) +} + +#[test] +fn doctest_split_import() { + check( + "split_import", + r#####" +use std::<|>collections::HashMap; +"#####, + r#####" +use std::{collections::HashMap}; +"#####, + ) +} diff --git a/docs/user/assists.md b/docs/user/assists.md index 34a95696cae2..e4d08a7dcadd 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -38,6 +38,22 @@ fn main() { } ``` +## `add_hash` + +Adds a hash to a raw string literal. + +```rust +// BEFORE +fn main() { + r#"Hello,┃ World!"#; +} + +// AFTER +fn main() { + r##"Hello, World!"##; +} +``` + ## `add_impl` Adds a new inherent impl for a type. @@ -266,6 +282,38 @@ fn main() { } ``` +## `make_raw_string` + +Adds `r#` to a plain string literal. + +```rust +// BEFORE +fn main() { + "Hello,┃ World!"; +} + +// AFTER +fn main() { + r#"Hello, World!"#; +} +``` + +## `make_usual_string` + +Turns a raw string into a plain string. + +```rust +// BEFORE +fn main() { + r#"Hello,┃ "World!""#; +} + +// AFTER +fn main() { + "Hello, \"World!\""; +} +``` + ## `merge_match_arms` Merges identical match arms. @@ -358,3 +406,74 @@ fn handle(action: Action) { } } ``` + +## `remove_dbg` + +Removes `dbg!()` macro call. + +```rust +// BEFORE +fn main() { + ┃dbg!(92); +} + +// AFTER +fn main() { + 92; +} +``` + +## `remove_hash` + +Removes a hash from a raw string literal. + +```rust +// BEFORE +fn main() { + r#"Hello,┃ World!"#; +} + +// AFTER +fn main() { + r"Hello, World!"; +} +``` + +## `replace_if_let_with_match` + +Replaces `if let` with an else branch with a `match` expression. + +```rust +// BEFORE +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + ┃if let Action::Move { distance } = action { + foo(distance) + } else { + bar() + } +} + +// AFTER +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move { distance } => foo(distance), + _ => bar(), + } +} +``` + +## `split_import` + +Wraps the tail of import into braces. + +```rust +// BEFORE +use std::┃collections::HashMap; + +// AFTER +use std::{collections::HashMap}; +``` diff --git a/docs/user/features.md b/docs/user/features.md index 2e213e34c380..7ae2ca7b6ee4 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -118,180 +118,6 @@ impl Debug<|> for Foo { } ``` -- Fill struct fields - -```rust -// before: -struct S<'a, D> { - a: u32, - b: String, - c: (i32, i32), - d: D, - r: &'a str, -} - -fn main() { - let s = S<|> {} -} - -// after: -struct S<'a, D> { - a: u32, - b: String, - c: (i32, i32), - d: D, - r: &'a str, -} - -fn main() { - let s = <|>S { - a: (), - b: (), - c: (), - d: (), - r: (), - } -} -``` - -- Remove `dbg!` - -```rust -// before: -fn foo(n: usize) { - if let Some(_) = dbg!(n.<|>checked_sub(4)) { - // ... - } -} - -// after: -fn foo(n: usize) { - if let Some(_) = n.<|>checked_sub(4) { - // ... - } -} -``` - -- Replace if-let with match: - -```rust -// before: -impl VariantData { - pub fn is_struct(&self) -> bool { - if <|>let VariantData::Struct(..) = *self { - true - } else { - false - } - } -} - -// after: -impl VariantData { - pub fn is_struct(&self) -> bool { - <|>match *self { - VariantData::Struct(..) => true, - _ => false, - } - } -} -``` - -- Split import - -```rust -// before: -use crate:<|>:db::{RootDatabase, FileSymbol}; -// after: -use crate::{<|>db::{RootDatabase, FileSymbol}}; -``` - -- Move if condition to match arm guard -```rust -// before: -fn f() { - let mut t = 'a'; - let chars = "abcd"; - match t { - '\r' => if chars.clone().next().is_some() { - t = 'e';<|> - false - }, - _ => true - } -} - -// after: -fn f() { - let mut t = 'a'; - let chars = "abcd"; - match t { - '\r' <|>if chars.clone().next().is_some() => { - t = 'e'; - false - }, - _ => true - } -} -``` - -- Make raw string unescaped - -```rust -// before: -fn f() { - let s = <|>"ab\ncd"; -} - -// after: -fn f() { - let s = <|>r#"ab -cd"#; -} -``` - -- Make usual string - -```rust -// before: -fn f() { - let s = <|>r#"abcd"#; -} - -// after: -fn f() { - let s = <|>"abcd"; -} -``` - -- Add hash - -```rust -// before: -fn f() { - let s = <|>r"abcd"; -} - -// after: -fn f() { - let s = <|>r#"abcd"#; -} -``` - -- Remove hash - -```rust -// before: -fn f() { - let s = <|>r#"abcd"#; -} - -// after: -fn f() { - let s = <|>r"abcd"; -} -``` - ### Magic Completions In addition to usual reference completion, rust-analyzer provides some ✨magic✨ From 8464c45086ee0f5e40a4c9e5e4a76cdfeb3a1ad2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 12:36:40 +0300 Subject: [PATCH 031/102] remove relative_path_buf workaround The upstream problem was fixed with the change to 1.0 --- crates/ra_db/src/lib.rs | 5 +---- crates/ra_hir/src/nameres/mod_resolution.rs | 13 +++---------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index fc5d6d39654c..0d1ab48438d0 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -134,10 +134,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { ) -> Option { let path = { let mut path = self.0.file_relative_path(anchor); - // Workaround for relative path API: turn `lib.rs` into ``. - if !path.pop() { - path = RelativePathBuf::default(); - } + assert!(path.pop()); path.push(relative_path); path.normalize() }; diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs index e8b8085142c7..334cdd692ac2 100644 --- a/crates/ra_hir/src/nameres/mod_resolution.rs +++ b/crates/ra_hir/src/nameres/mod_resolution.rs @@ -30,10 +30,7 @@ impl ModDir { None => path.push(&name.to_string()), Some(attr_path) => { if self.root_non_dir_owner { - // Workaround for relative path API: turn `lib.rs` into ``. - if !path.pop() { - path = RelativePathBuf::default(); - } + assert!(path.pop()); } path.push(attr_path); } @@ -48,17 +45,13 @@ impl ModDir { name: &Name, attr_path: Option<&SmolStr>, ) -> Result<(FileId, ModDir), RelativePathBuf> { - let empty_path = RelativePathBuf::default(); let file_id = file_id.original_file(db); let mut candidate_files = Vec::new(); match attr_to_path(attr_path) { Some(attr_path) => { - let base = if self.root_non_dir_owner { - self.path.parent().unwrap_or(&empty_path) - } else { - &self.path - }; + let base = + if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path }; candidate_files.push(base.join(attr_path)) } None => { From 3e7e3fdf163363896c1273d764e7665a00078ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20El=C3=ADs=20Ebenesersson?= Date: Sun, 27 Oct 2019 21:18:54 +0900 Subject: [PATCH 032/102] extend selection in trait bound extends to plus When multiple traits bounds are present, expanded selection from a single trait bound will include the nearest plus sign (and whitespace after) before including the whole trait bound. --- crates/ra_ide_api/src/extend_selection.rs | 82 ++++++++++++++++++++--- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs index 602757e92eb0..4b7bfc0b11e8 100644 --- a/crates/ra_ide_api/src/extend_selection.rs +++ b/crates/ra_ide_api/src/extend_selection.rs @@ -5,7 +5,7 @@ use ra_syntax::{ algo::find_covering_element, ast::{self, AstNode, AstToken}, Direction, NodeOrToken, - SyntaxKind::*, + SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, TextRange, TextUnit, TokenAtOffset, T, }; @@ -29,10 +29,12 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken { } } -/// Extend list item selection to include nearby comma and whitespace. +/// Extend list item selection to include nearby delimiter and whitespace. fn extend_list_item(node: &SyntaxNode) -> Option { fn is_single_line_ws(node: &SyntaxToken) -> bool { node.kind() == WHITESPACE && !node.text().contains('\n') } - fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option { + fn nearby_delimiter( + delimiter_kind: SyntaxKind, + node: &SyntaxNode, + dir: Direction, + ) -> Option { node.siblings_with_tokens(dir) .skip(1) .skip_while(|node| match node { @@ -161,19 +167,26 @@ fn extend_list_item(node: &SyntaxNode) -> Option { }) .next() .and_then(|it| it.into_token()) - .filter(|node| node.kind() == T![,]) + .filter(|node| node.kind() == delimiter_kind) } - if let Some(comma_node) = nearby_comma(node, Direction::Prev) { - return Some(TextRange::from_to(comma_node.text_range().start(), node.text_range().end())); + let delimiter = match node.kind() { + TYPE_BOUND => T![+], + _ => T![,], + }; + if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) { + return Some(TextRange::from_to( + delimiter_node.text_range().start(), + node.text_range().end(), + )); } - if let Some(comma_node) = nearby_comma(node, Direction::Next) { - // Include any following whitespace when comma if after list item. - let final_node = comma_node + if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) { + // Include any following whitespace when delimiter is after list item. + let final_node = delimiter_node .next_sibling_or_token() .and_then(|it| it.into_token()) .filter(|node| is_single_line_ws(node)) - .unwrap_or(comma_node); + .unwrap_or(delimiter_node); return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end())); } @@ -387,4 +400,53 @@ fn bar(){} &["foo", "\" fn foo() {\""], ); } + + #[test] + fn test_extend_trait_bounds_list_in_where_clause() { + do_check( + r#" +fn foo() + where + R: req::Request + 'static, + R::Params: DeserializeOwned<|> + panic::UnwindSafe + 'static, + R::Result: Serialize + 'static, +"#, + &[ + "DeserializeOwned", + "DeserializeOwned + ", + "DeserializeOwned + panic::UnwindSafe + 'static", + "R::Params: DeserializeOwned + panic::UnwindSafe + 'static", + "R::Params: DeserializeOwned + panic::UnwindSafe + 'static,", + ], + ); + do_check(r#"fn foo() where T: <|>Copy"#, &["Copy"]); + do_check(r#"fn foo() where T: <|>Copy + Display"#, &["Copy", "Copy + "]); + do_check(r#"fn foo() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); + do_check(r#"fn foo() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); + do_check(r#"fn foo() where T: Copy + <|>Display"#, &["Display", "+ Display"]); + do_check(r#"fn foo() where T: Copy + <|>Display + Sync"#, &["Display", "+ Display"]); + do_check(r#"fn foo() where T: Copy +<|>Display"#, &["Display", "+Display"]); + } + + #[test] + fn test_extend_trait_bounds_list_inline() { + do_check(r#"fn fooCopy>() {}"#, &["Copy"]); + do_check(r#"fn fooCopy + Display>() {}"#, &["Copy", "Copy + "]); + do_check(r#"fn fooCopy +Display>() {}"#, &["Copy", "Copy +"]); + do_check(r#"fn fooCopy+Display>() {}"#, &["Copy", "Copy+"]); + do_check(r#"fn fooDisplay>() {}"#, &["Display", "+ Display"]); + do_check(r#"fn fooDisplay + Sync>() {}"#, &["Display", "+ Display"]); + do_check(r#"fn fooDisplay>() {}"#, &["Display", "+Display"]); + do_check( + r#"fn foo + Display, U: Copy>() {}"#, + &[ + "Copy", + "Copy + ", + "Copy + Display", + "T: Copy + Display", + "T: Copy + Display, ", + "", + ], + ); + } } From 73532e900e2ea3b012d540d6dd9df9b564fb5852 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 16:46:49 +0300 Subject: [PATCH 033/102] rename auto_import -> add_import We are long way from auto imports at the moment --- .../assists/{auto_import.rs => add_import.rs} | 144 +++++++++--------- crates/ra_assists/src/lib.rs | 6 +- 2 files changed, 75 insertions(+), 75 deletions(-) rename crates/ra_assists/src/assists/{auto_import.rs => add_import.rs} (97%) diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/add_import.rs similarity index 97% rename from crates/ra_assists/src/assists/auto_import.rs rename to crates/ra_assists/src/assists/add_import.rs index a1c2aaa7299a..048bc49c8b2c 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -1,18 +1,65 @@ //! FIXME: write short doc here use hir::{self, db::HirDatabase}; -use ra_text_edit::TextEditBuilder; - -use crate::{ - assist_ctx::{Assist, AssistCtx}, - AssistId, -}; use ra_syntax::{ ast::{self, NameOwner}, AstNode, Direction, SmolStr, SyntaxKind::{PATH, PATH_SEGMENT}, SyntaxNode, TextRange, T, }; +use ra_text_edit::TextEditBuilder; + +use crate::{ + assist_ctx::{Assist, AssistCtx}, + AssistId, +}; + +pub(crate) fn add_import(mut ctx: AssistCtx) -> Option { + let path: ast::Path = ctx.find_node_at_offset()?; + // We don't want to mess with use statements + if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { + return None; + } + + let hir_path = hir::Path::from_ast(path.clone())?; + let segments = collect_hir_path_segments(&hir_path)?; + if segments.len() < 2 { + return None; + } + + if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { + if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { + ctx.add_action( + AssistId("add_import"), + format!("import {} in mod {}", fmt_segments(&segments), name.text()), + |edit| { + apply_auto_import( + item_list.syntax(), + &path, + &segments, + edit.text_edit_builder(), + ); + }, + ); + } + } else { + let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; + ctx.add_action( + AssistId("add_import"), + format!("import {} in the current file", fmt_segments(&segments)), + |edit| { + apply_auto_import( + current_file.syntax(), + &path, + &segments, + edit.text_edit_builder(), + ); + }, + ); + } + + ctx.build() +} fn collect_path_segments_raw( segments: &mut Vec, @@ -546,53 +593,6 @@ pub fn auto_import_text_edit( } } -pub(crate) fn auto_import(mut ctx: AssistCtx) -> Option { - let path: ast::Path = ctx.find_node_at_offset()?; - // We don't want to mess with use statements - if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { - return None; - } - - let hir_path = hir::Path::from_ast(path.clone())?; - let segments = collect_hir_path_segments(&hir_path)?; - if segments.len() < 2 { - return None; - } - - if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { - if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { - ctx.add_action( - AssistId("auto_import"), - format!("import {} in mod {}", fmt_segments(&segments), name.text()), - |edit| { - apply_auto_import( - item_list.syntax(), - &path, - &segments, - edit.text_edit_builder(), - ); - }, - ); - } - } else { - let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; - ctx.add_action( - AssistId("auto_import"), - format!("import {} in the current file", fmt_segments(&segments)), - |edit| { - apply_auto_import( - current_file.syntax(), - &path, - &segments, - edit.text_edit_builder(), - ); - }, - ); - } - - ctx.build() -} - #[cfg(test)] mod tests { use super::*; @@ -601,7 +601,7 @@ mod tests { #[test] fn test_auto_import_add_use_no_anchor() { check_assist( - auto_import, + add_import, " std::fmt::Debug<|> ", @@ -615,7 +615,7 @@ Debug<|> #[test] fn test_auto_import_add_use_no_anchor_with_item_below() { check_assist( - auto_import, + add_import, " std::fmt::Debug<|> @@ -636,7 +636,7 @@ fn main() { #[test] fn test_auto_import_add_use_no_anchor_with_item_above() { check_assist( - auto_import, + add_import, " fn main() { } @@ -657,7 +657,7 @@ Debug<|> #[test] fn test_auto_import_add_use_no_anchor_2seg() { check_assist( - auto_import, + add_import, " std::fmt<|>::Debug ", @@ -672,7 +672,7 @@ fmt<|>::Debug #[test] fn test_auto_import_add_use() { check_assist( - auto_import, + add_import, " use stdx; @@ -692,7 +692,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_file_use_other_anchor() { check_assist( - auto_import, + add_import, " impl std::fmt::Debug<|> for Foo { } @@ -709,7 +709,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_add_use_other_anchor_indent() { check_assist( - auto_import, + add_import, " impl std::fmt::Debug<|> for Foo { } @@ -726,7 +726,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_split_different() { check_assist( - auto_import, + add_import, " use std::fmt; @@ -745,7 +745,7 @@ impl io<|> for Foo { #[test] fn test_auto_import_split_self_for_use() { check_assist( - auto_import, + add_import, " use std::fmt; @@ -764,7 +764,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_split_self_for_target() { check_assist( - auto_import, + add_import, " use std::fmt::Debug; @@ -783,7 +783,7 @@ impl fmt<|> for Foo { #[test] fn test_auto_import_add_to_nested_self_nested() { check_assist( - auto_import, + add_import, " use std::fmt::{Debug, nested::{Display}}; @@ -802,7 +802,7 @@ impl nested<|> for Foo { #[test] fn test_auto_import_add_to_nested_self_already_included() { check_assist( - auto_import, + add_import, " use std::fmt::{Debug, nested::{self, Display}}; @@ -821,7 +821,7 @@ impl nested<|> for Foo { #[test] fn test_auto_import_add_to_nested_nested() { check_assist( - auto_import, + add_import, " use std::fmt::{Debug, nested::{Display}}; @@ -840,7 +840,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_split_common_target_longer() { check_assist( - auto_import, + add_import, " use std::fmt::Debug; @@ -859,7 +859,7 @@ impl Display<|> for Foo { #[test] fn test_auto_import_split_common_use_longer() { check_assist( - auto_import, + add_import, " use std::fmt::nested::Debug; @@ -878,7 +878,7 @@ impl Display<|> for Foo { #[test] fn test_auto_import_alias() { check_assist( - auto_import, + add_import, " use std::fmt as foo; @@ -897,7 +897,7 @@ impl Debug<|> for Foo { #[test] fn test_auto_import_not_applicable_one_segment() { check_assist_not_applicable( - auto_import, + add_import, " impl foo<|> for Foo { } @@ -908,7 +908,7 @@ impl foo<|> for Foo { #[test] fn test_auto_import_not_applicable_in_use() { check_assist_not_applicable( - auto_import, + add_import, " use std::fmt<|>; ", @@ -918,7 +918,7 @@ use std::fmt<|>; #[test] fn test_auto_import_add_use_no_anchor_in_mod_mod() { check_assist( - auto_import, + add_import, " mod foo { mod bar { diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index de576324fbeb..7c226572a54f 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -17,7 +17,7 @@ use ra_syntax::{TextRange, TextUnit}; use ra_text_edit::TextEdit; pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; -pub use crate::assists::auto_import::auto_import_text_edit; +pub use crate::assists::add_import::auto_import_text_edit; /// Unique identifier of the assist, should not be shown to the user /// directly. @@ -106,7 +106,7 @@ mod assists { mod replace_if_let_with_match; mod split_import; mod remove_dbg; - pub(crate) mod auto_import; + pub(crate) mod add_import; mod add_missing_impl_members; mod move_guard; mod move_bounds; @@ -127,7 +127,7 @@ mod assists { replace_if_let_with_match::replace_if_let_with_match, split_import::split_import, remove_dbg::remove_dbg, - auto_import::auto_import, + add_import::add_import, add_missing_impl_members::add_missing_impl_members, add_missing_impl_members::add_missing_default_members, inline_local_variable::inline_local_varialbe, From be0f48f7cf801a6330d3e6a65b3352d544d32f63 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 16:48:20 +0300 Subject: [PATCH 034/102] move public stuff to top --- crates/ra_assists/src/assists/add_import.rs | 52 ++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index 048bc49c8b2c..149d1403fec5 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -14,6 +14,31 @@ use crate::{ AssistId, }; +// This function produces sequence of text edits into edit +// to import the target path in the most appropriate scope given +// the cursor position +pub fn auto_import_text_edit( + // Ideally the position of the cursor, used to + position: &SyntaxNode, + // The statement to use as anchor (last resort) + anchor: &SyntaxNode, + // The path to import as a sequence of strings + target: &[SmolStr], + edit: &mut TextEditBuilder, +) { + let container = position.ancestors().find_map(|n| { + if let Some(module) = ast::Module::cast(n.clone()) { + return module.item_list().map(|it| it.syntax().clone()); + } + ast::SourceFile::cast(n).map(|it| it.syntax().clone()) + }); + + if let Some(container) = container { + let action = best_action_for_target(container, anchor.clone(), target); + make_assist(&action, target, edit); + } +} + pub(crate) fn add_import(mut ctx: AssistCtx) -> Option { let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements @@ -552,7 +577,7 @@ fn apply_auto_import( } } -pub fn collect_hir_path_segments(path: &hir::Path) -> Option> { +fn collect_hir_path_segments(path: &hir::Path) -> Option> { let mut ps = Vec::::with_capacity(10); match path.kind { hir::PathKind::Abs => ps.push("".into()), @@ -568,31 +593,6 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option> { Some(ps) } -// This function produces sequence of text edits into edit -// to import the target path in the most appropriate scope given -// the cursor position -pub fn auto_import_text_edit( - // Ideally the position of the cursor, used to - position: &SyntaxNode, - // The statement to use as anchor (last resort) - anchor: &SyntaxNode, - // The path to import as a sequence of strings - target: &[SmolStr], - edit: &mut TextEditBuilder, -) { - let container = position.ancestors().find_map(|n| { - if let Some(module) = ast::Module::cast(n.clone()) { - return module.item_list().map(|it| it.syntax().clone()); - } - ast::SourceFile::cast(n).map(|it| it.syntax().clone()) - }); - - if let Some(container) = container { - let action = best_action_for_target(container, anchor.clone(), target); - make_assist(&action, target, edit); - } -} - #[cfg(test)] mod tests { use super::*; From 3a64a85a5279ab0fcd45b2712cb544929e86f2a0 Mon Sep 17 00:00:00 2001 From: Wesley Norris Date: Sat, 26 Oct 2019 16:24:48 -0400 Subject: [PATCH 035/102] Fixes #2054. This adds the `flip_trait_bound` assist which allows for the swapping of two trait bounds in a trait list that are next to each other. --- .../src/assists/flip_trait_bound.rs | 32 +++++++++++++++++++ crates/ra_assists/src/lib.rs | 2 ++ 2 files changed, 34 insertions(+) create mode 100644 crates/ra_assists/src/assists/flip_trait_bound.rs diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs new file mode 100644 index 000000000000..a2c954ec5fa9 --- /dev/null +++ b/crates/ra_assists/src/assists/flip_trait_bound.rs @@ -0,0 +1,32 @@ +//! Assist for swapping traits inside of a trait bound list +//! +//! E.g. `A + B` => `B + A` when the cursor is placed by the `+` inside of a +//! trait bound list + +use hir::db::HirDatabase; +use ra_syntax::{algo::non_trivia_sibling, ast::TypeBoundList, Direction, T}; + +use crate::{Assist, AssistCtx, AssistId}; + +/// Flip trait bound assist. +pub(crate) fn flip_trait_bound(mut ctx: AssistCtx) -> Option { + // Make sure we're in a `TypeBoundList` + ctx.node_at_offset::()?; + + // We want to replicate the behavior of `flip_binexpr` by only suggesting + // the assist when the cursor is on a `+` + let plus = ctx.token_at_offset().find(|tkn| tkn.kind() == T![+])?; + + let (before, after) = ( + non_trivia_sibling(plus.clone().into(), Direction::Prev)?, + non_trivia_sibling(plus.clone().into(), Direction::Next)?, + ); + + ctx.add_action(AssistId("flip_trait_bound"), "flip trait bound", |edit| { + edit.target(plus.text_range()); + edit.replace(before.text_range(), after.to_string()); + edit.replace(after.text_range(), before.to_string()); + }); + + ctx.build() +} diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index de576324fbeb..871d499601dd 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -97,6 +97,7 @@ mod assists { mod apply_demorgan; mod flip_comma; mod flip_binexpr; + mod flip_trait_bound; mod change_visibility; mod fill_match_arms; mod merge_match_arms; @@ -123,6 +124,7 @@ mod assists { merge_match_arms::merge_match_arms, flip_comma::flip_comma, flip_binexpr::flip_binexpr, + flip_trait_bound::flip_trait_bound, introduce_variable::introduce_variable, replace_if_let_with_match::replace_if_let_with_match, split_import::split_import, From fc2fc8528b699faf0993e607c842165ac65052f5 Mon Sep 17 00:00:00 2001 From: Wesley Norris Date: Sat, 26 Oct 2019 16:27:50 -0400 Subject: [PATCH 036/102] Add tests for the trait bound flip assist. Co-authored-by: vlthr --- .../src/assists/flip_trait_bound.rs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs index a2c954ec5fa9..203092d03fce 100644 --- a/crates/ra_assists/src/assists/flip_trait_bound.rs +++ b/crates/ra_assists/src/assists/flip_trait_bound.rs @@ -30,3 +30,79 @@ pub(crate) fn flip_trait_bound(mut ctx: AssistCtx) -> Option where T: A <|>+ B + C { }", "+") + } + + #[test] + fn flip_trait_bound_not_applicable_for_single_trait_bound() { + check_assist_not_applicable(flip_trait_bound, "struct S where T: <|>A { }") + } + + #[test] + fn flip_trait_bound_works_for_struct() { + check_assist( + flip_trait_bound, + "struct S where T: A <|>+ B { }", + "struct S where T: B <|>+ A { }", + ) + } + + #[test] + fn flip_trait_bound_works_for_trait_impl() { + check_assist( + flip_trait_bound, + "impl X for S where T: A +<|> B { }", + "impl X for S where T: B +<|> A { }", + ) + } + + #[test] + fn flip_trait_bound_works_for_fn() { + check_assist(flip_trait_bound, "fn f+ B>(t: T) { }", "fn f+ A>(t: T) { }") + } + + #[test] + fn flip_trait_bound_works_for_fn_where_clause() { + check_assist( + flip_trait_bound, + "fn f(t: T) where T: A +<|> B { }", + "fn f(t: T) where T: B +<|> A { }", + ) + } + + #[test] + fn flip_trait_bound_works_for_lifetime() { + check_assist( + flip_trait_bound, + "fn f(t: T) where T: A <|>+ 'static { }", + "fn f(t: T) where T: 'static <|>+ A { }", + ) + } + + #[test] + fn flip_trait_bound_works_for_complex_bounds() { + check_assist( + flip_trait_bound, + "struct S where T: A <|>+ b_mod::B + C { }", + "struct S where T: b_mod::B <|>+ A + C { }", + ) + } + + #[test] + fn flip_trait_bound_works_for_long_bounds() { + check_assist( + flip_trait_bound, + "struct S where T: A + B + C + D + E + F +<|> G + H + I + J { }", + "struct S where T: A + B + C + D + E + G +<|> F + H + I + J { }", + ) + } +} From 85c64ec7bed4fba183f8ed22c96241c7baec3972 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 16:56:53 +0300 Subject: [PATCH 037/102] use new api for flip_trait_bound assist --- .../src/assists/flip_trait_bound.rs | 33 ++++++++++++------- crates/ra_assists/src/doc_tests.rs | 12 ++++++- crates/ra_assists/src/doc_tests/generated.rs | 13 ++++++++ docs/user/assists.md | 12 +++++++ 4 files changed, 58 insertions(+), 12 deletions(-) diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs index 203092d03fce..1625b241f12f 100644 --- a/crates/ra_assists/src/assists/flip_trait_bound.rs +++ b/crates/ra_assists/src/assists/flip_trait_bound.rs @@ -1,21 +1,32 @@ -//! Assist for swapping traits inside of a trait bound list -//! -//! E.g. `A + B` => `B + A` when the cursor is placed by the `+` inside of a -//! trait bound list - use hir::db::HirDatabase; -use ra_syntax::{algo::non_trivia_sibling, ast::TypeBoundList, Direction, T}; +use ra_syntax::{ + algo::non_trivia_sibling, + ast::{self, AstNode}, + Direction, T, +}; use crate::{Assist, AssistCtx, AssistId}; -/// Flip trait bound assist. +// Assist: flip_trait_bound +// +// Flips two trait bounds. +// +// ``` +// fn foo Copy>() { } +// ``` +// -> +// ``` +// fn foo() { } +// ``` pub(crate) fn flip_trait_bound(mut ctx: AssistCtx) -> Option { - // Make sure we're in a `TypeBoundList` - ctx.node_at_offset::()?; - // We want to replicate the behavior of `flip_binexpr` by only suggesting // the assist when the cursor is on a `+` - let plus = ctx.token_at_offset().find(|tkn| tkn.kind() == T![+])?; + let plus = ctx.find_token_at_offset(T![+])?; + + // Make sure we're in a `TypeBoundList` + if ast::TypeBoundList::cast(plus.parent()).is_none() { + return None; + } let (before, after) = ( non_trivia_sibling(plus.clone().into(), Direction::Prev)?, diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 0ccf9d7308e8..6e1e3de843e6 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs @@ -17,7 +17,17 @@ fn check(assist_id: &str, before: &str, after: &str) { let (_assist_id, action) = crate::assists(&db, frange) .into_iter() .find(|(id, _)| id.id.0 == assist_id) - .unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id)); + .unwrap_or_else(|| { + panic!( + "\n\nAssist is not applicable: {}\nAvailable assists: {}", + assist_id, + crate::assists(&db, frange) + .into_iter() + .map(|(id, _)| id.id.0) + .collect::>() + .join(", ") + ) + }); let actual = action.edit.apply(&before); assert_eq_text!(after, &actual); diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index b8d335911ffa..ebe49aecfe20 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -255,6 +255,19 @@ fn main() { ) } +#[test] +fn doctest_flip_trait_bound() { + check( + "flip_trait_bound", + r#####" +fn foo Copy>() { } +"#####, + r#####" +fn foo() { } +"#####, + ) +} + #[test] fn doctest_inline_local_variable() { check( diff --git a/docs/user/assists.md b/docs/user/assists.md index e4d08a7dcadd..b1fe44d84055 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -248,6 +248,18 @@ fn main() { } ``` +## `flip_trait_bound` + +Flips two trait bounds. + +```rust +// BEFORE +fn foo() { } + +// AFTER +fn foo() { } +``` + ## `inline_local_variable` Inlines local variable. From 9e638c9f3ee68784cd93ec0458b0c92c18776f06 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 17:26:51 +0300 Subject: [PATCH 038/102] simplify --- crates/ra_assists/src/assists/add_import.rs | 43 +++++++-------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index 149d1403fec5..7aa66b1fec67 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -52,36 +52,18 @@ pub(crate) fn add_import(mut ctx: AssistCtx) -> Option return None; } - if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) { - if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) { - ctx.add_action( - AssistId("add_import"), - format!("import {} in mod {}", fmt_segments(&segments), name.text()), - |edit| { - apply_auto_import( - item_list.syntax(), - &path, - &segments, - edit.text_edit_builder(), - ); - }, - ); + let module = path.syntax().ancestors().find_map(ast::Module::cast); + let anchor = match module.and_then(|it| it.item_list()) { + Some(item_list) => item_list.syntax().clone(), + None => { + let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; + current_file.syntax().clone() } - } else { - let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; - ctx.add_action( - AssistId("add_import"), - format!("import {} in the current file", fmt_segments(&segments)), - |edit| { - apply_auto_import( - current_file.syntax(), - &path, - &segments, - edit.text_edit_builder(), - ); - }, - ); - } + }; + + ctx.add_action(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| { + apply_auto_import(&anchor, &path, &segments, edit.text_edit_builder()); + }); ctx.build() } @@ -595,9 +577,10 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option> { #[cfg(test)] mod tests { - use super::*; use crate::helpers::{check_assist, check_assist_not_applicable}; + use super::*; + #[test] fn test_auto_import_add_use_no_anchor() { check_assist( From cda6355de23825c201d02e6062cb2dd414e98bf9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 17:35:37 +0300 Subject: [PATCH 039/102] simplify AssistCtx API We never actually use ability to create multiple actions out of a single context --- crates/ra_assists/src/assist_ctx.rs | 10 ++-- crates/ra_assists/src/assists/add_derive.rs | 8 ++- .../src/assists/add_explicit_type.rs | 7 ++- crates/ra_assists/src/assists/add_impl.rs | 8 ++- crates/ra_assists/src/assists/add_import.rs | 12 ++--- .../src/assists/add_missing_impl_members.rs | 8 ++- .../ra_assists/src/assists/apply_demorgan.rs | 7 ++- .../src/assists/change_visibility.rs | 18 +++---- crates/ra_assists/src/assists/early_return.rs | 7 ++- .../ra_assists/src/assists/fill_match_arms.rs | 8 ++- crates/ra_assists/src/assists/flip_binexpr.rs | 8 ++- crates/ra_assists/src/assists/flip_comma.rs | 8 ++- .../src/assists/flip_trait_bound.rs | 8 ++- .../src/assists/inline_local_variable.rs | 8 ++- .../src/assists/introduce_variable.rs | 8 ++- .../src/assists/merge_match_arms.rs | 8 ++- crates/ra_assists/src/assists/move_bounds.rs | 52 ++++++++----------- crates/ra_assists/src/assists/move_guard.rs | 14 +++-- crates/ra_assists/src/assists/raw_string.rs | 28 +++++----- crates/ra_assists/src/assists/remove_dbg.rs | 8 ++- .../src/assists/replace_if_let_with_match.rs | 8 ++- crates/ra_assists/src/assists/split_import.rs | 8 ++- 22 files changed, 102 insertions(+), 157 deletions(-) diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index c527366791fb..c5e9056afb18 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -82,12 +82,12 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { f(ctx) } - pub(crate) fn add_action( - &mut self, + pub(crate) fn add_assist( + mut self, id: AssistId, label: impl Into, f: impl FnOnce(&mut AssistBuilder), - ) -> &mut Self { + ) -> Option { let label = AssistLabel { label: label.into(), id }; match &mut self.assist { Assist::Unresolved(labels) => labels.push(label), @@ -100,10 +100,6 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { labels_actions.push((label, action)); } } - self - } - - pub(crate) fn build(self) -> Option { Some(self.assist) } diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index d1e925b71f20..764b17bd8dc4 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs @@ -25,10 +25,10 @@ use crate::{Assist, AssistCtx, AssistId}; // y: u32, // } // ``` -pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option { +pub(crate) fn add_derive(ctx: AssistCtx) -> Option { let nominal = ctx.find_node_at_offset::()?; let node_start = derive_insertion_offset(&nominal)?; - ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { + ctx.add_assist(AssistId("add_derive"), "add `#[derive]`", |edit| { let derive_attr = nominal .attrs() .filter_map(|x| x.as_simple_call()) @@ -44,9 +44,7 @@ pub(crate) fn add_derive(mut ctx: AssistCtx) -> Option }; edit.target(nominal.syntax().text_range()); edit.set_cursor(offset) - }); - - ctx.build() + }) } // Insert `derive` after doc comments. diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index ffbdc0b6294a..ddda1a0f2c66 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs @@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId}; // let x: i32 = 92; // } // ``` -pub(crate) fn add_explicit_type(mut ctx: AssistCtx) -> Option { +pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option { let stmt = ctx.find_node_at_offset::()?; let expr = stmt.initializer()?; let pat = stmt.pat()?; @@ -47,11 +47,10 @@ pub(crate) fn add_explicit_type(mut ctx: AssistCtx) -> Option< return None; } - ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { + ctx.add_assist(AssistId("add_explicit_type"), "add explicit type", |edit| { edit.target(pat_range); edit.insert(name_range.end(), format!(": {}", ty.display(db))); - }); - ctx.build() + }) } /// Returns true if any type parameter is unknown diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index fd3588d24967..7da0cfd0d326 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs @@ -27,10 +27,10 @@ use crate::{Assist, AssistCtx, AssistId}; // // } // ``` -pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { +pub(crate) fn add_impl(ctx: AssistCtx) -> Option { let nominal = ctx.find_node_at_offset::()?; let name = nominal.name()?; - ctx.add_action(AssistId("add_impl"), "add impl", |edit| { + ctx.add_assist(AssistId("add_impl"), "add impl", |edit| { edit.target(nominal.syntax().text_range()); let type_params = nominal.type_param_list(); let start_offset = nominal.syntax().text_range().end(); @@ -54,9 +54,7 @@ pub(crate) fn add_impl(mut ctx: AssistCtx) -> Option { edit.set_cursor(start_offset + TextUnit::of_str(&buf)); buf.push_str("\n}"); edit.insert(start_offset, buf); - }); - - ctx.build() + }) } #[cfg(test)] diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index 7aa66b1fec67..c522d6a5a71c 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -39,7 +39,7 @@ pub fn auto_import_text_edit( } } -pub(crate) fn add_import(mut ctx: AssistCtx) -> Option { +pub(crate) fn add_import(ctx: AssistCtx) -> Option { let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { @@ -53,7 +53,7 @@ pub(crate) fn add_import(mut ctx: AssistCtx) -> Option } let module = path.syntax().ancestors().find_map(ast::Module::cast); - let anchor = match module.and_then(|it| it.item_list()) { + let position = match module.and_then(|it| it.item_list()) { Some(item_list) => item_list.syntax().clone(), None => { let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?; @@ -61,11 +61,9 @@ pub(crate) fn add_import(mut ctx: AssistCtx) -> Option } }; - ctx.add_action(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| { - apply_auto_import(&anchor, &path, &segments, edit.text_edit_builder()); - }); - - ctx.build() + ctx.add_assist(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| { + apply_auto_import(&position, &path, &segments, edit.text_edit_builder()); + }) } fn collect_path_segments_raw( diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 2585f3045426..41de239219fb 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs @@ -91,7 +91,7 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx) -> O } fn add_missing_impl_members_inner( - mut ctx: AssistCtx, + ctx: AssistCtx, mode: AddMissingImplMembersMode, assist_id: &'static str, label: &'static str, @@ -133,7 +133,7 @@ fn add_missing_impl_members_inner( return None; } - ctx.add_action(AssistId(assist_id), label, |edit| { + ctx.add_assist(AssistId(assist_id), label, |edit| { let n_existing_items = impl_item_list.impl_items().count(); let items = missing_items .into_iter() @@ -150,9 +150,7 @@ fn add_missing_impl_members_inner( edit.replace_ast(impl_item_list, new_impl_item_list); edit.set_cursor(cursor_position); - }); - - ctx.build() + }) } fn add_body(fn_def: ast::FnDef) -> ast::FnDef { diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 8d5984a583ad..068da1774d98 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -23,7 +23,7 @@ use crate::{Assist, AssistCtx, AssistId}; // if !(x == 4 && y) {} // } // ``` -pub(crate) fn apply_demorgan(mut ctx: AssistCtx) -> Option { +pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option { let expr = ctx.find_node_at_offset::()?; let op = expr.op_kind()?; let op_range = expr.op_token()?.text_range(); @@ -39,13 +39,12 @@ pub(crate) fn apply_demorgan(mut ctx: AssistCtx) -> Option) -> Option) -> Option { +fn add_vis(ctx: AssistCtx) -> Option { let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, _ => false, @@ -57,13 +57,11 @@ fn add_vis(mut ctx: AssistCtx) -> Option { (vis_offset(field.syntax()), ident.text_range()) }; - ctx.add_action(AssistId("change_visibility"), "make pub(crate)", |edit| { + ctx.add_assist(AssistId("change_visibility"), "make pub(crate)", |edit| { edit.target(target); edit.insert(offset, "pub(crate) "); edit.set_cursor(offset); - }); - - ctx.build() + }) } fn vis_offset(node: &SyntaxNode) -> TextUnit { @@ -77,24 +75,20 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit { .unwrap_or_else(|| node.text_range().start()) } -fn change_vis(mut ctx: AssistCtx, vis: ast::Visibility) -> Option { +fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option { if vis.syntax().text() == "pub" { - ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { + return ctx.add_assist(AssistId("change_visibility"), "change to pub(crate)", |edit| { edit.target(vis.syntax().text_range()); edit.replace(vis.syntax().text_range(), "pub(crate)"); edit.set_cursor(vis.syntax().text_range().start()) }); - - return ctx.build(); } if vis.syntax().text() == "pub(crate)" { - ctx.add_action(AssistId("change_visibility"), "change to pub", |edit| { + return ctx.add_assist(AssistId("change_visibility"), "change to pub", |edit| { edit.target(vis.syntax().text_range()); edit.replace(vis.syntax().text_range(), "pub"); edit.set_cursor(vis.syntax().text_range().start()); }); - - return ctx.build(); } None } diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 75822dc65a56..e839d831e06f 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -35,7 +35,7 @@ use crate::{ // bar(); // } // ``` -pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> Option { +pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let expr = if_expr.condition()?.expr()?; let then_block = if_expr.then_branch()?.block()?; @@ -75,7 +75,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; let cursor_position = ctx.frange.range.start(); - ctx.add_action(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { + ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); let new_if_expr = if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); @@ -105,8 +105,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx) -> edit.target(if_expr.syntax().text_range()); edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); edit.set_cursor(cursor_position); - }); - ctx.build() + }) } #[cfg(test)] diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index c62c0efbefd6..2b74f355c6ab 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // } // ``` -pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option { +pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option { let match_expr = ctx.find_node_at_offset::()?; let match_arm_list = match_expr.match_arm_list()?; @@ -53,7 +53,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx) -> Option) -> Option bool { diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index 9765d5dddc08..386045eb0a05 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs @@ -18,7 +18,7 @@ use crate::{Assist, AssistCtx, AssistId}; // let _ = 2 + 90; // } // ``` -pub(crate) fn flip_binexpr(mut ctx: AssistCtx) -> Option { +pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option { let expr = ctx.find_node_at_offset::()?; let lhs = expr.lhs()?.syntax().clone(); let rhs = expr.rhs()?.syntax().clone(); @@ -34,16 +34,14 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx) -> Option) -> Option { +pub(crate) fn flip_comma(ctx: AssistCtx) -> Option { let comma = ctx.find_token_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; @@ -29,13 +29,11 @@ pub(crate) fn flip_comma(mut ctx: AssistCtx) -> Option return None; } - ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { + ctx.add_assist(AssistId("flip_comma"), "flip comma", |edit| { edit.target(comma.text_range()); edit.replace(prev.text_range(), next.to_string()); edit.replace(next.text_range(), prev.to_string()); - }); - - ctx.build() + }) } #[cfg(test)] diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs index 1625b241f12f..6017b39dd84b 100644 --- a/crates/ra_assists/src/assists/flip_trait_bound.rs +++ b/crates/ra_assists/src/assists/flip_trait_bound.rs @@ -18,7 +18,7 @@ use crate::{Assist, AssistCtx, AssistId}; // ``` // fn foo() { } // ``` -pub(crate) fn flip_trait_bound(mut ctx: AssistCtx) -> Option { +pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option { // We want to replicate the behavior of `flip_binexpr` by only suggesting // the assist when the cursor is on a `+` let plus = ctx.find_token_at_offset(T![+])?; @@ -33,13 +33,11 @@ pub(crate) fn flip_trait_bound(mut ctx: AssistCtx) -> Option) -> Option { +pub(crate) fn inline_local_varialbe(ctx: AssistCtx) -> Option { let let_stmt = ctx.find_node_at_offset::()?; let bind_pat = match let_stmt.pat()? { ast::Pat::BindPat(pat) => pat, @@ -93,7 +93,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx) -> Opt let init_str = initializer_expr.syntax().text().to_string(); let init_in_paren = format!("({})", &init_str); - ctx.add_action( + ctx.add_assist( AssistId("inline_local_variable"), "inline local variable", move |edit: &mut AssistBuilder| { @@ -107,9 +107,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx) -> Opt } edit.set_cursor(delete_range.start()) }, - ); - - ctx.build() + ) } #[cfg(test)] diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs index 8245dc99f57e..0623d44759e5 100644 --- a/crates/ra_assists/src/assists/introduce_variable.rs +++ b/crates/ra_assists/src/assists/introduce_variable.rs @@ -28,7 +28,7 @@ use crate::{Assist, AssistCtx, AssistId}; // var_name * 4; // } // ``` -pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option { +pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option { if ctx.frange.range.is_empty() { return None; } @@ -43,7 +43,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option if indent.kind() != WHITESPACE { return None; } - ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| { + ctx.add_assist(AssistId("introduce_variable"), "introduce variable", move |edit| { let mut buf = String::new(); let cursor_offset = if wrap_in_block { @@ -88,9 +88,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option } } edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); - }); - - ctx.build() + }) } /// Check whether the node is a valid expression which can be extracted to a variable. diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index b0c4ee78b59e..e9f2cae91d35 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs @@ -26,7 +26,7 @@ use ra_syntax::ast::{AstNode, MatchArm}; // } // } // ``` -pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option { +pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option { let current_arm = ctx.find_node_at_offset::()?; // We check if the following match arm matches this one. We could, but don't, @@ -52,7 +52,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option bool { a.pats().any(|x| match x { ra_syntax::ast::Pat::PlaceholderPat(..) => true, @@ -80,9 +80,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx) -> Option) -> Option { +pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option { let type_param_list = ctx.find_node_at_offset::()?; let mut type_params = type_param_list.type_params(); @@ -46,38 +46,30 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx) _ => return None, }; - ctx.add_action( - AssistId("move_bounds_to_where_clause"), - "move_bounds_to_where_clause", - |edit| { - let new_params = type_param_list - .type_params() - .filter(|it| it.type_bound_list().is_some()) - .map(|type_param| { - let without_bounds = type_param.remove_bounds(); - (type_param, without_bounds) - }); + ctx.add_assist(AssistId("move_bounds_to_where_clause"), "move_bounds_to_where_clause", |edit| { + let new_params = type_param_list + .type_params() + .filter(|it| it.type_bound_list().is_some()) + .map(|type_param| { + let without_bounds = type_param.remove_bounds(); + (type_param, without_bounds) + }); - let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); - edit.replace_ast(type_param_list.clone(), new_type_param_list); + let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); + edit.replace_ast(type_param_list.clone(), new_type_param_list); - let where_clause = { - let predicates = type_param_list.type_params().filter_map(build_predicate); - make::where_clause(predicates) - }; + let where_clause = { + let predicates = type_param_list.type_params().filter_map(build_predicate); + make::where_clause(predicates) + }; - let to_insert = match anchor.prev_sibling_or_token() { - Some(ref elem) if elem.kind() == WHITESPACE => { - format!("{} ", where_clause.syntax()) - } - _ => format!(" {}", where_clause.syntax()), - }; - edit.insert(anchor.text_range().start(), to_insert); - edit.target(type_param_list.syntax().text_range()); - }, - ); - - ctx.build() + let to_insert = match anchor.prev_sibling_or_token() { + Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), + _ => format!(" {}", where_clause.syntax()), + }; + edit.insert(anchor.text_range().start(), to_insert); + edit.target(type_param_list.syntax().text_range()); + }) } fn build_predicate(param: ast::TypeParam) -> Option { diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index e820a73c8d90..b49ec6172ac3 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs @@ -32,7 +32,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // } // ``` -pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Option { +pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option { let match_arm = ctx.find_node_at_offset::()?; let guard = match_arm.guard()?; let space_before_guard = guard.syntax().prev_sibling_or_token(); @@ -41,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op let arm_expr = match_arm.expr()?; let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); - ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { + ctx.add_assist(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { edit.target(guard.syntax().text_range()); let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { Some(tok) => { @@ -61,8 +61,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op edit.set_cursor( arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount, ); - }); - ctx.build() + }) } // Assist: move_arm_cond_to_match_guard @@ -90,7 +89,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx) -> Op // } // } // ``` -pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) -> Option { +pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option { let match_arm: MatchArm = ctx.find_node_at_offset::()?; let last_match_pat = match_arm.pats().last()?; @@ -110,7 +109,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) let buf = format!(" if {}", cond.syntax().text()); - ctx.add_action( + ctx.add_assist( AssistId("move_arm_cond_to_match_guard"), "move condition to match guard", |edit| { @@ -127,8 +126,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx) edit.insert(last_match_pat.syntax().text_range().end(), buf); edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1)); }, - ); - ctx.build() + ) } #[cfg(test)] diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 2df48a8380cb..86bbaeeeff78 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -22,7 +22,7 @@ use crate::{Assist, AssistCtx, AssistId}; // r#"Hello, World!"#; // } // ``` -pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option { +pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(STRING)?; let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; @@ -41,7 +41,7 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx) -> Option) -> Option) -> Option) -> Option { +pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); let usual_string_range = find_usual_string_range(text)?; - ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { + ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| { edit.target(token.text_range()); // parse inside string to escape `"` let start_of_inside = usual_string_range.start().to_usize() + 1; @@ -80,8 +79,7 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option< let inside_str = &text[start_of_inside..end_of_inside]; let escaped = inside_str.escape_default().to_string(); edit.replace(token.text_range(), format!("\"{}\"", escaped)); - }); - ctx.build() + }) } // Assist: add_hash @@ -99,14 +97,13 @@ pub(crate) fn make_usual_string(mut ctx: AssistCtx) -> Option< // r##"Hello, World!"##; // } // ``` -pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { +pub(crate) fn add_hash(ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; - ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { + ctx.add_assist(AssistId("add_hash"), "add hash to raw string", |edit| { edit.target(token.text_range()); edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#"); edit.insert(token.text_range().end(), "#"); - }); - ctx.build() + }) } // Assist: remove_hash @@ -124,14 +121,14 @@ pub(crate) fn add_hash(mut ctx: AssistCtx) -> Option { // r"Hello, World!"; // } // ``` -pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option { +pub(crate) fn remove_hash(ctx: AssistCtx) -> Option { let token = ctx.find_token_at_offset(RAW_STRING)?; let text = token.text().as_str(); if text.starts_with("r\"") { // no hash to remove return None; } - ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { + ctx.add_assist(AssistId("remove_hash"), "remove hash from raw string", |edit| { edit.target(token.text_range()); let result = &text[2..text.len() - 1]; let result = if result.starts_with("\"") { @@ -142,8 +139,7 @@ pub(crate) fn remove_hash(mut ctx: AssistCtx) -> Option usize { diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index 44b8de81452e..aedf8747f22a 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs @@ -21,7 +21,7 @@ use crate::{Assist, AssistCtx, AssistId}; // 92; // } // ``` -pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option { +pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option { let macro_call = ctx.find_node_at_offset::()?; if !is_valid_macrocall(¯o_call, "dbg")? { @@ -58,13 +58,11 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx) -> Option text.slice(without_parens).to_string() }; - ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { + ctx.add_assist(AssistId("remove_dbg"), "remove dbg!()", |edit| { edit.target(macro_call.syntax().text_range()); edit.replace(macro_range, macro_content); edit.set_cursor(cursor_pos); - }); - - ctx.build() + }) } /// Verifies that the given macro_call actually matches the given name diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index 58ef2ff20673..dff84d86516c 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs @@ -31,7 +31,7 @@ use crate::{Assist, AssistCtx, AssistId}; // } // } // ``` -pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> Option { +pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; let pat = cond.pat()?; @@ -42,14 +42,12 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx) -> ast::ElseBranch::IfExpr(_) => return None, }; - ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { + ctx.add_assist(AssistId("replace_if_let_with_match"), "replace with match", |edit| { let match_expr = build_match_expr(expr, pat, then_block, else_block); edit.target(if_expr.syntax().text_range()); edit.replace_node_and_indent(if_expr.syntax(), match_expr); edit.set_cursor(if_expr.syntax().text_range().start()) - }); - - ctx.build() + }) } fn build_match_expr( diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index 8d8a2898787f..5f8d6b0be1ff 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs @@ -16,7 +16,7 @@ use crate::{Assist, AssistCtx, AssistId}; // ``` // use std::{collections::HashMap}; // ``` -pub(crate) fn split_import(mut ctx: AssistCtx) -> Option { +pub(crate) fn split_import(ctx: AssistCtx) -> Option { let colon_colon = ctx.find_token_at_offset(T![::])?; let path = ast::Path::cast(colon_colon.parent())?; let top_path = successors(Some(path), |it| it.parent_path()).last()?; @@ -32,14 +32,12 @@ pub(crate) fn split_import(mut ctx: AssistCtx) -> Option top_path.syntax().text_range().end(), }; - ctx.add_action(AssistId("split_import"), "split import", |edit| { + ctx.add_assist(AssistId("split_import"), "split import", |edit| { edit.target(colon_colon.text_range()); edit.insert(l_curly, "{"); edit.insert(r_curly, "}"); edit.set_cursor(l_curly + TextUnit::of_str("{")); - }); - - ctx.build() + }) } #[cfg(test)] From b6fcacd96d26e7edaf37bda852b8b3ad104d4c90 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 17:49:39 +0300 Subject: [PATCH 040/102] move all assists to use generated docs --- crates/ra_assists/src/assists/add_import.rs | 21 +++++++++++++++----- crates/ra_assists/src/doc_tests/generated.rs | 15 ++++++++++++++ docs/user/assists.md | 14 +++++++++++++ docs/user/features.md | 20 +++---------------- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index c522d6a5a71c..e87fae1af0a5 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -1,5 +1,3 @@ -//! FIXME: write short doc here - use hir::{self, db::HirDatabase}; use ra_syntax::{ ast::{self, NameOwner}, @@ -14,9 +12,9 @@ use crate::{ AssistId, }; -// This function produces sequence of text edits into edit -// to import the target path in the most appropriate scope given -// the cursor position +/// This function produces sequence of text edits into edit +/// to import the target path in the most appropriate scope given +/// the cursor position pub fn auto_import_text_edit( // Ideally the position of the cursor, used to position: &SyntaxNode, @@ -39,6 +37,19 @@ pub fn auto_import_text_edit( } } +// Assist: add_import +// +// Adds a use statement for a given fully-qualified path. +// +// ``` +// fn process(map: std::collections::<|>HashMap) {} +// ``` +// -> +// ``` +// use std::collections::HashMap; +// +// fn process(map: HashMap) {} +// ``` pub(crate) fn add_import(ctx: AssistCtx) -> Option { let path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index ebe49aecfe20..1bee76f59a33 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -141,6 +141,21 @@ impl T for () { ) } +#[test] +fn doctest_add_import() { + check( + "add_import", + r#####" +fn process(map: std::collections::<|>HashMap) {} +"#####, + r#####" +use std::collections::HashMap; + +fn process(map: HashMap) {} +"#####, + ) +} + #[test] fn doctest_apply_demorgan() { check( diff --git a/docs/user/assists.md b/docs/user/assists.md index b1fe44d84055..303353e74294 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md @@ -136,6 +136,20 @@ impl T for () { } ``` +## `add_import` + +Adds a use statement for a given fully-qualified path. + +```rust +// BEFORE +fn process(map: std::collections::┃HashMap) {} + +// AFTER +use std::collections::HashMap; + +fn process(map: HashMap) {} +``` + ## `apply_demorgan` Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). diff --git a/docs/user/features.md b/docs/user/features.md index 7ae2ca7b6ee4..c160dd70bd95 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -99,24 +99,10 @@ Stop `cargo watch` ### Assists (Code Actions) -These are triggered in a particular context via light bulb. We use custom code on -the VS Code side to be able to position cursor. `<|>` signifies cursor +Assists, or code actions, are small local refactorings, available in a particular context. +They are usually triggered by a shortcut or by clicking a light bulb icon in the editor. -See [assists.md](./assists.md) - -- Import path - -```rust -// before: -impl std::fmt::Debug<|> for Foo { -} - -// after: -use std::fmt::Debug; - -impl Debug<|> for Foo { -} -``` +See [assists.md](./assists.md) for the list of available assists. ### Magic Completions From ad3fe316c616cbc5640cff19048eabac8941ed01 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 27 Oct 2019 18:22:14 +0300 Subject: [PATCH 041/102] further simplify assists --- crates/ra_assists/src/assist_ctx.rs | 36 ++++++------- crates/ra_assists/src/lib.rs | 83 ++++++++--------------------- 2 files changed, 37 insertions(+), 82 deletions(-) diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index c5e9056afb18..1908bdec90df 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs @@ -14,8 +14,8 @@ use crate::{AssistAction, AssistId, AssistLabel}; #[derive(Clone, Debug)] pub(crate) enum Assist { - Unresolved(Vec), - Resolved(Vec<(AssistLabel, AssistAction)>), + Unresolved { label: AssistLabel }, + Resolved { label: AssistLabel, action: AssistAction }, } /// `AssistCtx` allows to apply an assist or check if it could be applied. @@ -54,7 +54,6 @@ pub(crate) struct AssistCtx<'a, DB> { pub(crate) frange: FileRange, source_file: SourceFile, should_compute_edit: bool, - assist: Assist, } impl<'a, DB> Clone for AssistCtx<'a, DB> { @@ -64,7 +63,6 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> { frange: self.frange, source_file: self.source_file.clone(), should_compute_edit: self.should_compute_edit, - assist: self.assist.clone(), } } } @@ -75,32 +73,30 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { F: FnOnce(AssistCtx) -> T, { let parse = db.parse(frange.file_id); - let assist = - if should_compute_edit { Assist::Resolved(vec![]) } else { Assist::Unresolved(vec![]) }; - let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit, assist }; + let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit }; f(ctx) } pub(crate) fn add_assist( - mut self, + self, id: AssistId, label: impl Into, f: impl FnOnce(&mut AssistBuilder), ) -> Option { let label = AssistLabel { label: label.into(), id }; - match &mut self.assist { - Assist::Unresolved(labels) => labels.push(label), - Assist::Resolved(labels_actions) => { - let action = { - let mut edit = AssistBuilder::default(); - f(&mut edit); - edit.build() - }; - labels_actions.push((label, action)); - } - } - Some(self.assist) + let assist = if self.should_compute_edit { + let action = { + let mut edit = AssistBuilder::default(); + f(&mut edit); + edit.build() + }; + Assist::Resolved { label, action } + } else { + Assist::Unresolved { label } + }; + + Some(assist) } pub(crate) fn token_at_offset(&self) -> TokenAtOffset { diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 7a1657d87f62..38599d4f173c 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -11,7 +11,6 @@ mod marks; mod doc_tests; use hir::db::HirDatabase; -use itertools::Itertools; use ra_db::FileRange; use ra_syntax::{TextRange, TextUnit}; use ra_text_edit::TextEdit; @@ -51,10 +50,10 @@ where .iter() .filter_map(|f| f(ctx.clone())) .map(|a| match a { - Assist::Unresolved(labels) => labels, - Assist::Resolved(..) => unreachable!(), + Assist::Unresolved { label } => label, + Assist::Resolved { .. } => unreachable!(), }) - .concat() + .collect() }) } @@ -73,10 +72,10 @@ where .iter() .filter_map(|f| f(ctx.clone())) .map(|a| match a { - Assist::Resolved(labels_actions) => labels_actions, - Assist::Unresolved(..) => unreachable!(), + Assist::Resolved { label, action } => (label, action), + Assist::Unresolved { .. } => unreachable!(), }) - .concat(); + .collect::>(); a.sort_by(|a, b| match (a.1.target, b.1.target) { (Some(a), Some(b)) => a.len().cmp(&b.len()), (Some(_), None) => Ordering::Less, @@ -158,39 +157,6 @@ mod helpers { assist: fn(AssistCtx) -> Option, before: &str, after: &str, - ) { - check_assist_nth_action(assist, before, after, 0) - } - - pub(crate) fn check_assist_range( - assist: fn(AssistCtx) -> Option, - before: &str, - after: &str, - ) { - check_assist_range_nth_action(assist, before, after, 0) - } - - pub(crate) fn check_assist_target( - assist: fn(AssistCtx) -> Option, - before: &str, - target: &str, - ) { - check_assist_target_nth_action(assist, before, target, 0) - } - - pub(crate) fn check_assist_range_target( - assist: fn(AssistCtx) -> Option, - before: &str, - target: &str, - ) { - check_assist_range_target_nth_action(assist, before, target, 0) - } - - pub(crate) fn check_assist_nth_action( - assist: fn(AssistCtx) -> Option, - before: &str, - after: &str, - index: usize, ) { let (before_cursor_pos, before) = extract_offset(before); let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); @@ -198,12 +164,11 @@ mod helpers { FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; let assist = AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); - let labels_actions = match assist { - Assist::Unresolved(_) => unreachable!(), - Assist::Resolved(labels_actions) => labels_actions, + let action = match assist { + Assist::Unresolved { .. } => unreachable!(), + Assist::Resolved { action, .. } => action, }; - let (_, action) = labels_actions.get(index).expect("expect assist action at index"); let actual = action.edit.apply(&before); let actual_cursor_pos = match action.cursor_position { None => action @@ -216,23 +181,21 @@ mod helpers { assert_eq_text!(after, &actual); } - pub(crate) fn check_assist_range_nth_action( + pub(crate) fn check_assist_range( assist: fn(AssistCtx) -> Option, before: &str, after: &str, - index: usize, ) { let (range, before) = extract_range(before); let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); let frange = FileRange { file_id, range }; let assist = AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); - let labels_actions = match assist { - Assist::Unresolved(_) => unreachable!(), - Assist::Resolved(labels_actions) => labels_actions, + let action = match assist { + Assist::Unresolved { .. } => unreachable!(), + Assist::Resolved { action, .. } => action, }; - let (_, action) = labels_actions.get(index).expect("expect assist action at index"); let mut actual = action.edit.apply(&before); if let Some(pos) = action.cursor_position { actual = add_cursor(&actual, pos); @@ -240,11 +203,10 @@ mod helpers { assert_eq_text!(after, &actual); } - pub(crate) fn check_assist_target_nth_action( + pub(crate) fn check_assist_target( assist: fn(AssistCtx) -> Option, before: &str, target: &str, - index: usize, ) { let (before_cursor_pos, before) = extract_offset(before); let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); @@ -252,33 +214,30 @@ mod helpers { FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; let assist = AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); - let labels_actions = match assist { - Assist::Unresolved(_) => unreachable!(), - Assist::Resolved(labels_actions) => labels_actions, + let action = match assist { + Assist::Unresolved { .. } => unreachable!(), + Assist::Resolved { action, .. } => action, }; - let (_, action) = labels_actions.get(index).expect("expect assist action at index"); let range = action.target.expect("expected target on action"); assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); } - pub(crate) fn check_assist_range_target_nth_action( + pub(crate) fn check_assist_range_target( assist: fn(AssistCtx) -> Option, before: &str, target: &str, - index: usize, ) { let (range, before) = extract_range(before); let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); let frange = FileRange { file_id, range }; let assist = AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); - let labels_actions = match assist { - Assist::Unresolved(_) => unreachable!(), - Assist::Resolved(labels_actions) => labels_actions, + let action = match assist { + Assist::Unresolved { .. } => unreachable!(), + Assist::Resolved { action, .. } => action, }; - let (_, action) = labels_actions.get(index).expect("expect assist action at index"); let range = action.target.expect("expected target on action"); assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); } From a0d55edc3873c7788ab2f91e394e53a5a77c16b8 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 12:26:44 -0400 Subject: [PATCH 042/102] Be more precise with function signatures Fixes #2093 --- crates/ra_ide_api/src/call_info.rs | 40 ++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 7d18be483c7b..c95133343d61 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -2,7 +2,7 @@ use ra_db::SourceDatabase; use ra_syntax::{ - algo::find_node_at_offset, + algo::ancestors_at_offset, ast::{self, ArgListOwner}, AstNode, SyntaxNode, TextUnit, }; @@ -82,13 +82,15 @@ enum FnCallNode { impl FnCallNode { fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option { - if let Some(expr) = find_node_at_offset::(syntax, offset) { - return Some(FnCallNode::CallExpr(expr)); - } - if let Some(expr) = find_node_at_offset::(syntax, offset) { - return Some(FnCallNode::MethodCallExpr(expr)); - } - None + ancestors_at_offset(syntax, offset).find_map(|node| { + if let Some(expr) = ast::CallExpr::cast(node.clone()) { + Some(FnCallNode::CallExpr(expr)) + } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) { + Some(FnCallNode::MethodCallExpr(expr)) + } else { + None + } + }) } fn name_ref(&self) -> Option { @@ -438,4 +440,26 @@ By default this method stops actor's `Context`."# let call_info = analysis.call_info(position).unwrap(); assert!(call_info.is_none()); } + + #[test] + fn test_nested_method_in_lamba() { + let info = call_info( + r#"struct Foo; + +impl Foo { + fn bar(&self, _: u32) { } +} + +fn bar(_: u32) { } + +fn main() { + let foo = Foo; + std::thread::spawn(move || foo.bar(<|>)); +}"#, + ); + + assert_eq!(info.parameters(), ["&self", "_: u32"]); + assert_eq!(info.active_parameter, Some(1)); + assert_eq!(info.label(), "fn bar(&self, _: u32)"); + } } From 17bd3e59f86a4da548c6c61dff9421dfdb31b65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20El=C3=ADs=20Ebenesersson?= Date: Mon, 28 Oct 2019 03:00:28 +0900 Subject: [PATCH 043/102] Fix panic on raw string assist Strings that do not contain two quotation marks would cause a slice indexing panic because code was assuming `find_usual_string_range` would return a string with two quotes, but it would incorrectly also return text ranges containing only a single quote. --- crates/ra_assists/src/assists/raw_string.rs | 39 ++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 2df48a8380cb..cb3a1e6e9230 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -159,10 +159,17 @@ fn count_hashes(s: &str) -> usize { } fn find_usual_string_range(s: &str) -> Option { - Some(TextRange::from_to( - TextUnit::from(s.find('"')? as u32), - TextUnit::from(s.rfind('"')? as u32), - )) + let left_quote = s.find('"')?; + let right_quote = s.rfind('"')?; + if left_quote == right_quote { + // `s` only contains one quote + None + } else { + Some(TextRange::from_to( + TextUnit::from(left_quote as u32), + TextUnit::from(right_quote as u32), + )) + } } #[cfg(test)] @@ -271,6 +278,30 @@ string"###; ) } + #[test] + fn make_raw_string_not_works_on_partial_string() { + check_assist_not_applicable( + make_raw_string, + r#" + fn f() { + let s = "foo<|> + } + "#, + ) + } + + #[test] + fn make_usual_string_not_works_on_partial_string() { + check_assist_not_applicable( + make_usual_string, + r#" + fn main() { + let s = r#"bar<|> + } + "#, + ) + } + #[test] fn add_hash_target() { check_assist_target( From 1438f38eb63e5a79350fa6c877d9960ab90e183d Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 16:56:25 -0400 Subject: [PATCH 044/102] Preserve whitespace at the end of doc comments Whitespace can have special meaning in markdown. For instance ending a line with three spaces will render a new line. Note that this behavior diverges from RLS. Fixes #1997 --- crates/ra_syntax/src/ast.rs | 24 ++++++++++++++++++++++-- crates/ra_syntax/src/ast/traits.rs | 7 +++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 1b2ce921a51c..a12da5be2ab4 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -173,7 +173,7 @@ fn test_doc_comment_single_line_block_strips_suffix_whitespace() { .ok() .unwrap(); let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!("this is mod foo", module.doc_comment_text().unwrap()); + assert_eq!("this is mod foo ", module.doc_comment_text().unwrap()); } #[test] @@ -191,7 +191,27 @@ fn test_doc_comment_multi_line_block_strips_suffix() { .ok() .unwrap(); let module = file.syntax().descendants().find_map(Module::cast).unwrap(); - assert_eq!(" this\n is\n mod foo", module.doc_comment_text().unwrap()); + assert_eq!( + " this\n is\n mod foo\n ", + module.doc_comment_text().unwrap() + ); +} + +#[test] +fn test_comments_preserve_trailing_whitespace() { + let file = SourceFile::parse( + r#" +/// Representation of a Realm. +/// In the specification these are called Realm Records. +struct Realm {}"#, + ) + .ok() + .unwrap(); + let def = file.syntax().descendants().find_map(StructDef::cast).unwrap(); + assert_eq!( + "Representation of a Realm. \nIn the specification these are called Realm Records.", + def.doc_comment_text().unwrap() + ); } #[test] diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index f275a49558d7..76313684eaba 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -120,7 +120,7 @@ pub trait DocCommentsOwner: AstNode { has_comments = true; let prefix_len = comment.prefix().len(); - let line = comment.text().as_str(); + let line: &str = comment.text().as_str(); // Determine if the prefix or prefix + 1 char is stripped let pos = @@ -136,7 +136,10 @@ pub trait DocCommentsOwner: AstNode { line.len() }; - line[pos..end].trim_end().to_owned() + // Note that we do not trim the end of the line here + // since whitespace can have special meaning at the end + // of a line in markdown. + line[pos..end].to_owned() }) .join("\n"); From 03adea962a37f4456bfe666864837ba66cbc8124 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 22:44:33 -0400 Subject: [PATCH 045/102] Update crates --- Cargo.lock | 80 +++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f8a4431d5a7..0206f16bc3bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,8 +108,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -171,7 +171,7 @@ dependencies = [ "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -288,7 +288,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -413,7 +413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -501,7 +501,7 @@ dependencies = [ "console 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -517,7 +517,7 @@ dependencies = [ [[package]] name = "itertools" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -624,7 +624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -634,7 +634,7 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -811,7 +811,7 @@ dependencies = [ "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -845,7 +845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -903,7 +903,7 @@ name = "ra_assists" version = "0.1.0" dependencies = [ "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "ra_db 0.1.0", "ra_fmt 0.1.0", @@ -970,7 +970,7 @@ dependencies = [ name = "ra_fmt" version = "0.1.0" dependencies = [ - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "ra_syntax 0.1.0", ] @@ -1007,7 +1007,7 @@ dependencies = [ "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1049,7 +1049,7 @@ dependencies = [ "ra_vfs_glob 0.1.0", "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", @@ -1081,7 +1081,7 @@ name = "ra_prof" version = "0.1.0" dependencies = [ "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1097,7 +1097,7 @@ dependencies = [ "ra_cfg 0.1.0", "ra_db 0.1.0", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1106,7 +1106,7 @@ name = "ra_syntax" version = "0.1.0" dependencies = [ "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ra_parser 0.1.0", "ra_text_edit 0.1.0", @@ -1180,7 +1180,7 @@ name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1224,7 +1224,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1370,7 +1370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1441,7 +1441,7 @@ dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1463,7 +1463,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1473,20 +1473,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1496,7 +1496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1506,7 +1506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1516,7 +1516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1535,7 +1535,7 @@ name = "smol_str" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1557,7 +1557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1673,7 +1673,7 @@ dependencies = [ "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1682,7 +1682,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1759,7 +1759,7 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1828,7 +1828,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" @@ -1839,7 +1839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d499dc062e841590a67230d853bce62d0abeb91304927871670b7c55c461349" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7" "checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45" @@ -1922,8 +1922,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" +"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" @@ -1932,7 +1932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" "checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579" From 5a59bc9fcbbacb3d214e5bb9490f66ccb0abf5cb Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 19:12:21 -0400 Subject: [PATCH 046/102] WIP: Expand signature help This is hacky but works for tuple structs. Proof of concept. --- crates/ra_ide_api/src/call_info.rs | 39 +++++++++++++++---- .../src/display/function_signature.rs | 29 +++++++++++++- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index c95133343d61..dfd6e69c5164 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -20,24 +20,27 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { //FIXME: apply subst let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; match callable_def { - hir::CallableDef::Function(it) => it, + hir::CallableDef::Function(it) => { + (CallInfo::with_fn(db, it), it.data(db).has_self_param()) + } + hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false), //FIXME: handle other callables _ => return None, } } - FnCallNode::MethodCallExpr(expr) => analyzer.resolve_method_call(&expr)?, + FnCallNode::MethodCallExpr(expr) => { + let function = analyzer.resolve_method_call(&expr)?; + (CallInfo::with_fn(db, function), function.data(db).has_self_param()) + } }; - let mut call_info = CallInfo::new(db, function); - // If we have a calling expression let's find which argument we are on let num_params = call_info.parameters().len(); - let has_self = function.data(db).has_self_param(); if num_params == 1 { if !has_self { @@ -115,12 +118,18 @@ impl FnCallNode { } impl CallInfo { - fn new(db: &RootDatabase, function: hir::Function) -> Self { + fn with_fn(db: &RootDatabase, function: hir::Function) -> Self { let signature = FunctionSignature::from_hir(db, function); CallInfo { signature, active_parameter: None } } + fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self { + let signature = FunctionSignature::from_struct(db, st); + + CallInfo { signature, active_parameter: None } + } + fn parameters(&self) -> &[String] { &self.signature.parameters } @@ -462,4 +471,20 @@ fn main() { assert_eq!(info.active_parameter, Some(1)); assert_eq!(info.label(), "fn bar(&self, _: u32)"); } + + fn works_for_tuple_structs() { + let info = call_info( + r#" +/// A cool tuple struct +struct TS(String, i32); +fn main() { + let s = TS("".into(), <|>); +}"#, + ); + + //assert_eq!(info.label(), "struct TS(String, i32)"); + assert_eq!(info.label(), "fn TS(0: {unknown}, 1: i32) -> TS"); + assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); + assert_eq!(info.active_parameter, Some(1)); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 43f022ccd46a..0697a0727dfe 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display}; -use hir::{Docs, Documentation, HasSource}; +use hir::{Docs, Documentation, HasSource, HirDisplay}; use join_to_string::join; use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; use std::convert::From; @@ -42,6 +42,33 @@ impl FunctionSignature { let ast_node = function.source(db).ast; FunctionSignature::from(&ast_node).with_doc_opt(doc) } + + pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Self { + let doc = st.docs(db); + + let node: ast::StructDef = st.source(db).ast; + + let params = st + .fields(db) + .into_iter() + .map(|field: hir::StructField| { + let name = field.name(db); + let ty = field.ty(db); + format!("{}: {}", name, ty.display(db)) + }) + .collect(); + + FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node.name().map(|n| n.text().to_string()), + parameters: /*param_list(node)*/ params, + generic_parameters: generic_parameters(&node), + where_predicates: where_predicates(&node), + doc: None, + } + .with_doc_opt(doc) + } } impl From<&'_ ast::FnDef> for FunctionSignature { From 55d4b06a53246c144be900877e6ac03237d6f8b4 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 20:11:02 -0400 Subject: [PATCH 047/102] Add disciminant --- crates/ra_ide_api/src/call_info.rs | 10 ++++------ .../ra_ide_api/src/display/function_signature.rs | 14 +++++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index dfd6e69c5164..29ae2f5520ee 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -29,8 +29,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option (CallInfo::with_struct(db, it), false), - //FIXME: handle other callables - _ => return None, + hir::CallableDef::EnumVariant(_it) => return None, } } FnCallNode::MethodCallExpr(expr) => { @@ -476,14 +475,13 @@ fn main() { let info = call_info( r#" /// A cool tuple struct -struct TS(String, i32); +struct TS(u32, i32); fn main() { - let s = TS("".into(), <|>); + let s = TS(0, <|>); }"#, ); - //assert_eq!(info.label(), "struct TS(String, i32)"); - assert_eq!(info.label(), "fn TS(0: {unknown}, 1: i32) -> TS"); + assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS"); assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 0697a0727dfe..6555f8619ee8 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -12,9 +12,16 @@ use crate::{ display::{generic_parameters, where_predicates}, }; +#[derive(Debug)] +pub enum SigKind { + Function, + Struct, +} + /// Contains information about a function signature #[derive(Debug)] pub struct FunctionSignature { + pub kind: SigKind, /// Optional visibility pub visibility: Option, /// Name of the function @@ -59,6 +66,7 @@ impl FunctionSignature { .collect(); FunctionSignature { + kind: SigKind::Struct, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), @@ -86,6 +94,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { } FunctionSignature { + kind: SigKind::Function, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node @@ -108,7 +117,10 @@ impl Display for FunctionSignature { } if let Some(name) = &self.name { - write!(f, "fn {}", name)?; + match self.kind { + SigKind::Function => write!(f, "fn {}", name)?, + SigKind::Struct => write!(f, "struct {}", name)?, + } } if !self.generic_parameters.is_empty() { From 49e89772f63e10ebeb3c8720bd0b0ef8244f6c4a Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 21:26:12 -0400 Subject: [PATCH 048/102] Preliminary enum variant support --- crates/ra_ide_api/src/call_info.rs | 32 +++++++++++++++- .../src/display/function_signature.rs | 37 ++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 29ae2f5520ee..e6bdaae6a6c5 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -29,7 +29,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option (CallInfo::with_struct(db, it), false), - hir::CallableDef::EnumVariant(_it) => return None, + hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false), } } FnCallNode::MethodCallExpr(expr) => { @@ -129,6 +129,12 @@ impl CallInfo { CallInfo { signature, active_parameter: None } } + fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self { + let signature = FunctionSignature::from_enum_variant(db, variant); + + CallInfo { signature, active_parameter: None } + } + fn parameters(&self) -> &[String] { &self.signature.parameters } @@ -485,4 +491,28 @@ fn main() { assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } + + #[test] + fn works_for_enum_variants() { + let info = call_info( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C(a: i32, b: i32) +} + +fn main() { + let a = E::A(<|>); +} + "#, + ); + + assert_eq!(info.label(), "E::A(0: i32)"); + assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); + assert_eq!(info.active_parameter, Some(0)); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 6555f8619ee8..6b169b3ae5ac 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -16,6 +16,7 @@ use crate::{ pub enum SigKind { Function, Struct, + EnumVariant, } /// Contains information about a function signature @@ -70,13 +71,46 @@ impl FunctionSignature { visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), - parameters: /*param_list(node)*/ params, + parameters: params, generic_parameters: generic_parameters(&node), where_predicates: where_predicates(&node), doc: None, } .with_doc_opt(doc) } + + pub(crate) fn from_enum_variant(db: &db::RootDatabase, variant: hir::EnumVariant) -> Self { + let doc = variant.docs(db); + + let parent_name = match variant.parent_enum(db).name(db) { + Some(name) => name.to_string(), + None => "missing".into(), + }; + + let name = format!("{}::{}", parent_name, variant.name(db).unwrap()); + + let params = variant + .fields(db) + .into_iter() + .map(|field: hir::StructField| { + let name = field.name(db); + let ty = field.ty(db); + format!("{}: {}", name, ty.display(db)) + }) + .collect(); + + FunctionSignature { + kind: SigKind::EnumVariant, + visibility: None, + name: Some(name), + ret_type: None, + parameters: params, + generic_parameters: vec![], + where_predicates: vec![], + doc: None, + } + .with_doc_opt(doc) + } } impl From<&'_ ast::FnDef> for FunctionSignature { @@ -120,6 +154,7 @@ impl Display for FunctionSignature { match self.kind { SigKind::Function => write!(f, "fn {}", name)?, SigKind::Struct => write!(f, "struct {}", name)?, + SigKind::EnumVariant => write!(f, "{}", name)?, } } From 44f2805fee20893865039f70b97105cac2baa994 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 22:03:58 -0400 Subject: [PATCH 049/102] Fix syntax --- crates/ra_ide_api/src/call_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index e6bdaae6a6c5..faae12e54163 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -502,7 +502,7 @@ enum E { /// Another B, /// And C - C(a: i32, b: i32) + C { a: i32, b: i32 } } fn main() { From 5a6db3ca297357b7fb6319ce9b096f4ec15e7997 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 28 Oct 2019 15:36:38 +0300 Subject: [PATCH 050/102] fix parsing of for loops inside expressions closes #2051 --- .../ra_parser/src/grammar/expressions/atom.rs | 3 +- .../parser/err/0024_many_type_parens.txt | 91 ++++++++-------- .../parser/ok/0059_loops_in_parens.rs | 5 + .../parser/ok/0059_loops_in_parens.txt | 101 ++++++++++++++++++ 4 files changed, 151 insertions(+), 49 deletions(-) create mode 100644 crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs create mode 100644 crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index 7454005c4e26..4952bd1891b5 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs @@ -56,7 +56,8 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = LIFETIME, ASYNC_KW, TRY_KW, - LOOP_KW + LOOP_KW, + FOR_KW, ]); const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt index 198daf7b41bf..0a93e11a5321 100644 --- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt +++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt @@ -179,50 +179,47 @@ SOURCE_FILE@[0; 240) ERROR@[148; 149) PLUS@[148; 149) "+" WHITESPACE@[149; 150) " " - EXPR_STMT@[150; 151) - PAREN_EXPR@[150; 151) + EXPR_STMT@[150; 180) + TUPLE_EXPR@[150; 180) L_PAREN@[150; 151) "(" - EXPR_STMT@[151; 157) - FOR_EXPR@[151; 157) - FOR_KW@[151; 154) "for" - ERROR@[154; 155) - L_ANGLE@[154; 155) "<" - ERROR@[155; 157) - LIFETIME@[155; 157) "\'a" - EXPR_STMT@[157; 158) - ERROR@[157; 158) - R_ANGLE@[157; 158) ">" - WHITESPACE@[158; 159) " " - EXPR_STMT@[159; 180) - BIN_EXPR@[159; 180) - BIN_EXPR@[159; 178) - BIN_EXPR@[159; 169) - BIN_EXPR@[159; 167) - PATH_EXPR@[159; 164) - PATH@[159; 164) - PATH_SEGMENT@[159; 164) - NAME_REF@[159; 164) - IDENT@[159; 164) "Trait" - L_ANGLE@[164; 165) "<" - ERROR@[165; 167) - LIFETIME@[165; 167) "\'a" - R_ANGLE@[167; 168) ">" - ERROR@[168; 169) - R_PAREN@[168; 169) ")" - WHITESPACE@[169; 170) " " - PLUS@[170; 171) "+" - WHITESPACE@[171; 172) " " - PAREN_EXPR@[172; 178) - L_PAREN@[172; 173) "(" - PATH_EXPR@[173; 177) - PATH@[173; 177) - PATH_SEGMENT@[173; 177) - NAME_REF@[173; 177) - IDENT@[173; 177) "Copy" - R_PAREN@[177; 178) ")" - R_ANGLE@[178; 179) ">" - ERROR@[179; 180) - SEMI@[179; 180) ";" + BIN_EXPR@[151; 180) + BIN_EXPR@[151; 178) + BIN_EXPR@[151; 169) + BIN_EXPR@[151; 167) + BIN_EXPR@[151; 164) + FOR_EXPR@[151; 157) + FOR_KW@[151; 154) "for" + ERROR@[154; 155) + L_ANGLE@[154; 155) "<" + ERROR@[155; 157) + LIFETIME@[155; 157) "\'a" + R_ANGLE@[157; 158) ">" + WHITESPACE@[158; 159) " " + PATH_EXPR@[159; 164) + PATH@[159; 164) + PATH_SEGMENT@[159; 164) + NAME_REF@[159; 164) + IDENT@[159; 164) "Trait" + L_ANGLE@[164; 165) "<" + ERROR@[165; 167) + LIFETIME@[165; 167) "\'a" + R_ANGLE@[167; 168) ">" + ERROR@[168; 169) + R_PAREN@[168; 169) ")" + WHITESPACE@[169; 170) " " + PLUS@[170; 171) "+" + WHITESPACE@[171; 172) " " + PAREN_EXPR@[172; 178) + L_PAREN@[172; 173) "(" + PATH_EXPR@[173; 177) + PATH@[173; 177) + PATH_SEGMENT@[173; 177) + NAME_REF@[173; 177) + IDENT@[173; 177) "Copy" + R_PAREN@[177; 178) ")" + R_ANGLE@[178; 179) ">" + ERROR@[179; 180) + SEMI@[179; 180) ";" WHITESPACE@[180; 185) "\n " LET_STMT@[185; 235) LET_KW@[185; 188) "let" @@ -307,18 +304,16 @@ error 146: expected expression error 147: expected SEMI error 148: expected expression error 149: expected SEMI -error 151: expected expression -error 151: expected R_PAREN -error 151: expected SEMI error 154: expected pattern error 155: expected IN_KW error 155: expected expression error 157: expected a block -error 157: expected expression -error 158: expected SEMI error 165: expected expression error 168: expected expression error 179: expected expression +error 180: expected COMMA +error 180: expected expression +error 180: expected R_PAREN error 180: expected SEMI error 215: expected COMMA error 215: expected R_ANGLE diff --git a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs new file mode 100644 index 000000000000..6e8b718aaf9a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs @@ -0,0 +1,5 @@ +fn main() { + Some(for _ in [1].into_iter() {}); + Some(loop { break; }); + Some(while true {}); +} diff --git a/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt new file mode 100644 index 000000000000..c011187ead5e --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt @@ -0,0 +1,101 @@ +SOURCE_FILE@[0; 105) + FN_DEF@[0; 104) + FN_KW@[0; 2) "fn" + WHITESPACE@[2; 3) " " + NAME@[3; 7) + IDENT@[3; 7) "main" + PARAM_LIST@[7; 9) + L_PAREN@[7; 8) "(" + R_PAREN@[8; 9) ")" + WHITESPACE@[9; 10) " " + BLOCK_EXPR@[10; 104) + BLOCK@[10; 104) + L_CURLY@[10; 11) "{" + WHITESPACE@[11; 16) "\n " + EXPR_STMT@[16; 50) + CALL_EXPR@[16; 49) + PATH_EXPR@[16; 20) + PATH@[16; 20) + PATH_SEGMENT@[16; 20) + NAME_REF@[16; 20) + IDENT@[16; 20) "Some" + ARG_LIST@[20; 49) + L_PAREN@[20; 21) "(" + FOR_EXPR@[21; 48) + FOR_KW@[21; 24) "for" + WHITESPACE@[24; 25) " " + PLACEHOLDER_PAT@[25; 26) + UNDERSCORE@[25; 26) "_" + WHITESPACE@[26; 27) " " + IN_KW@[27; 29) "in" + WHITESPACE@[29; 30) " " + METHOD_CALL_EXPR@[30; 45) + ARRAY_EXPR@[30; 33) + L_BRACK@[30; 31) "[" + LITERAL@[31; 32) + INT_NUMBER@[31; 32) "1" + R_BRACK@[32; 33) "]" + DOT@[33; 34) "." + NAME_REF@[34; 43) + IDENT@[34; 43) "into_iter" + ARG_LIST@[43; 45) + L_PAREN@[43; 44) "(" + R_PAREN@[44; 45) ")" + WHITESPACE@[45; 46) " " + BLOCK_EXPR@[46; 48) + BLOCK@[46; 48) + L_CURLY@[46; 47) "{" + R_CURLY@[47; 48) "}" + R_PAREN@[48; 49) ")" + SEMI@[49; 50) ";" + WHITESPACE@[50; 55) "\n " + EXPR_STMT@[55; 77) + CALL_EXPR@[55; 76) + PATH_EXPR@[55; 59) + PATH@[55; 59) + PATH_SEGMENT@[55; 59) + NAME_REF@[55; 59) + IDENT@[55; 59) "Some" + ARG_LIST@[59; 76) + L_PAREN@[59; 60) "(" + LOOP_EXPR@[60; 75) + LOOP_KW@[60; 64) "loop" + WHITESPACE@[64; 65) " " + BLOCK_EXPR@[65; 75) + BLOCK@[65; 75) + L_CURLY@[65; 66) "{" + WHITESPACE@[66; 67) " " + EXPR_STMT@[67; 73) + BREAK_EXPR@[67; 72) + BREAK_KW@[67; 72) "break" + SEMI@[72; 73) ";" + WHITESPACE@[73; 74) " " + R_CURLY@[74; 75) "}" + R_PAREN@[75; 76) ")" + SEMI@[76; 77) ";" + WHITESPACE@[77; 82) "\n " + EXPR_STMT@[82; 102) + CALL_EXPR@[82; 101) + PATH_EXPR@[82; 86) + PATH@[82; 86) + PATH_SEGMENT@[82; 86) + NAME_REF@[82; 86) + IDENT@[82; 86) "Some" + ARG_LIST@[86; 101) + L_PAREN@[86; 87) "(" + WHILE_EXPR@[87; 100) + WHILE_KW@[87; 92) "while" + WHITESPACE@[92; 93) " " + CONDITION@[93; 97) + LITERAL@[93; 97) + TRUE_KW@[93; 97) "true" + WHITESPACE@[97; 98) " " + BLOCK_EXPR@[98; 100) + BLOCK@[98; 100) + L_CURLY@[98; 99) "{" + R_CURLY@[99; 100) "}" + R_PAREN@[100; 101) ")" + SEMI@[101; 102) ";" + WHITESPACE@[102; 103) "\n" + R_CURLY@[103; 104) "}" + WHITESPACE@[104; 105) "\n" From ddf25e9481d79abb6b583a195fd26b8ca1b9f060 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 28 Oct 2019 08:42:17 -0400 Subject: [PATCH 051/102] formatting --- crates/ra_ide_api/src/call_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index faae12e54163..25363a1d94ca 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -476,7 +476,7 @@ fn main() { assert_eq!(info.active_parameter, Some(1)); assert_eq!(info.label(), "fn bar(&self, _: u32)"); } - + fn works_for_tuple_structs() { let info = call_info( r#" From 01238a6fd7d89f97ea05d90b95d3244f1596dc93 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Mon, 28 Oct 2019 10:48:40 -0400 Subject: [PATCH 052/102] Filter out non callable versions of Struct/EnumVariant --- crates/ra_ide_api/src/call_info.rs | 52 +++++++++++--- .../src/display/function_signature.rs | 70 +++++++++++-------- 2 files changed, 84 insertions(+), 38 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 25363a1d94ca..d947ac50c2fc 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -28,8 +28,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { (CallInfo::with_fn(db, it), it.data(db).has_self_param()) } - hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false), - hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false), + hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it)?, false), + hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it)?, false), } } FnCallNode::MethodCallExpr(expr) => { @@ -123,16 +123,16 @@ impl CallInfo { CallInfo { signature, active_parameter: None } } - fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self { - let signature = FunctionSignature::from_struct(db, st); + fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option { + let signature = FunctionSignature::from_struct(db, st)?; - CallInfo { signature, active_parameter: None } + Some(CallInfo { signature, active_parameter: None }) } - fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self { - let signature = FunctionSignature::from_enum_variant(db, variant); + fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option { + let signature = FunctionSignature::from_enum_variant(db, variant)?; - CallInfo { signature, active_parameter: None } + Some(CallInfo { signature, active_parameter: None }) } fn parameters(&self) -> &[String] { @@ -477,6 +477,7 @@ fn main() { assert_eq!(info.label(), "fn bar(&self, _: u32)"); } + #[test] fn works_for_tuple_structs() { let info = call_info( r#" @@ -487,11 +488,23 @@ fn main() { }"#, ); - assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS"); + assert_eq!(info.label(), "struct TS(u32, i32) -> TS"); assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } + #[test] + #[should_panic] + fn cant_call_named_structs() { + let _ = call_info( + r#" +struct TS { x: u32, y: i32 } +fn main() { + let s = TS(<|>); +}"#, + ); + } + #[test] fn works_for_enum_variants() { let info = call_info( @@ -515,4 +528,25 @@ fn main() { assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); assert_eq!(info.active_parameter, Some(0)); } + + #[test] + #[should_panic] + fn cant_call_enum_records() { + let _ = call_info( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C { a: i32, b: i32 } +} + +fn main() { + let a = E::C(<|>); +} + "#, + ); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 6b169b3ae5ac..736b5d3dbeda 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -51,36 +51,46 @@ impl FunctionSignature { FunctionSignature::from(&ast_node).with_doc_opt(doc) } - pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Self { - let doc = st.docs(db); - + pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Option { let node: ast::StructDef = st.source(db).ast; + match node.kind() { + ast::StructKind::Named(_) => return None, + _ => (), + }; let params = st .fields(db) .into_iter() .map(|field: hir::StructField| { - let name = field.name(db); let ty = field.ty(db); - format!("{}: {}", name, ty.display(db)) + format!("{}", ty.display(db)) }) .collect(); - FunctionSignature { - kind: SigKind::Struct, - visibility: node.visibility().map(|n| n.syntax().text().to_string()), - name: node.name().map(|n| n.text().to_string()), - ret_type: node.name().map(|n| n.text().to_string()), - parameters: params, - generic_parameters: generic_parameters(&node), - where_predicates: where_predicates(&node), - doc: None, - } - .with_doc_opt(doc) + Some( + FunctionSignature { + kind: SigKind::Struct, + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node.name().map(|n| n.text().to_string()), + parameters: params, + generic_parameters: generic_parameters(&node), + where_predicates: where_predicates(&node), + doc: None, + } + .with_doc_opt(st.docs(db)), + ) } - pub(crate) fn from_enum_variant(db: &db::RootDatabase, variant: hir::EnumVariant) -> Self { - let doc = variant.docs(db); + pub(crate) fn from_enum_variant( + db: &db::RootDatabase, + variant: hir::EnumVariant, + ) -> Option { + let node: ast::EnumVariant = variant.source(db).ast; + match node.kind() { + ast::StructKind::Named(_) | ast::StructKind::Unit => return None, + _ => (), + }; let parent_name = match variant.parent_enum(db).name(db) { Some(name) => name.to_string(), @@ -99,17 +109,19 @@ impl FunctionSignature { }) .collect(); - FunctionSignature { - kind: SigKind::EnumVariant, - visibility: None, - name: Some(name), - ret_type: None, - parameters: params, - generic_parameters: vec![], - where_predicates: vec![], - doc: None, - } - .with_doc_opt(doc) + Some( + FunctionSignature { + kind: SigKind::EnumVariant, + visibility: None, + name: Some(name), + ret_type: None, + parameters: params, + generic_parameters: vec![], + where_predicates: vec![], + doc: None, + } + .with_doc_opt(variant.docs(db)), + ) } } From 54d3e47318930c7a443b1498ff88d365920abe39 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 28 Oct 2019 20:29:57 +0300 Subject: [PATCH 053/102] weaken requirements of AstDef --- crates/ra_hir/src/ids.rs | 46 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 499dcafea2eb..518ea32e99e8 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -11,7 +11,7 @@ use ra_prof::profile; use ra_syntax::{ast, AstNode, Parse, SyntaxNode}; use crate::{ - db::{AstDatabase, DefDatabase, InternDatabase}, + db::{AstDatabase, InternDatabase}, AstId, Crate, FileAstId, Module, Source, }; @@ -238,13 +238,13 @@ pub(crate) struct LocationCtx { file_id: HirFileId, } -impl<'a, DB: DefDatabase> LocationCtx<&'a DB> { +impl<'a, DB> LocationCtx<&'a DB> { pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { LocationCtx { db, module, file_id } } } -impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> { +impl<'a, DB: AstDatabase> LocationCtx<&'a DB> { pub(crate) fn to_def(self, ast: &N) -> DEF where N: AstNode, @@ -255,24 +255,24 @@ impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> { } pub(crate) trait AstItemDef: salsa::InternKey + Clone { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self; - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc; + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self; + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc; - fn from_ast(ctx: LocationCtx<&(impl AstDatabase + DefDatabase)>, ast: &N) -> Self { + fn from_ast(ctx: LocationCtx<&impl AstDatabase>, ast: &N) -> Self { let items = ctx.db.ast_id_map(ctx.file_id); let item_id = items.ast_id(ast); Self::from_ast_id(ctx, item_id) } - fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId) -> Self { + fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId) -> Self { let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; Self::intern(ctx.db, loc) } - fn source(self, db: &(impl AstDatabase + DefDatabase)) -> Source { + fn source(self, db: &impl AstDatabase) -> Source { let loc = self.lookup_intern(db); let ast = loc.ast_id.to_node(db); Source { file_id: loc.ast_id.file_id(), ast } } - fn module(self, db: &impl DefDatabase) -> Module { + fn module(self, db: &impl InternDatabase) -> Module { let loc = self.lookup_intern(db); loc.module } @@ -283,10 +283,10 @@ pub struct FunctionId(salsa::InternId); impl_intern_key!(FunctionId); impl AstItemDef for FunctionId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_function(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_function(self) } } @@ -295,10 +295,10 @@ impl AstItemDef for FunctionId { pub struct StructId(salsa::InternId); impl_intern_key!(StructId); impl AstItemDef for StructId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_struct(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_struct(self) } } @@ -307,10 +307,10 @@ impl AstItemDef for StructId { pub struct EnumId(salsa::InternId); impl_intern_key!(EnumId); impl AstItemDef for EnumId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_enum(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_enum(self) } } @@ -319,10 +319,10 @@ impl AstItemDef for EnumId { pub struct ConstId(salsa::InternId); impl_intern_key!(ConstId); impl AstItemDef for ConstId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_const(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_const(self) } } @@ -331,10 +331,10 @@ impl AstItemDef for ConstId { pub struct StaticId(salsa::InternId); impl_intern_key!(StaticId); impl AstItemDef for StaticId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_static(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_static(self) } } @@ -343,10 +343,10 @@ impl AstItemDef for StaticId { pub struct TraitId(salsa::InternId); impl_intern_key!(TraitId); impl AstItemDef for TraitId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_trait(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_trait(self) } } @@ -355,10 +355,10 @@ impl AstItemDef for TraitId { pub struct TypeAliasId(salsa::InternId); impl_intern_key!(TypeAliasId); impl AstItemDef for TypeAliasId { - fn intern(db: &impl DefDatabase, loc: ItemLoc) -> Self { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { db.intern_type_alias(loc) } - fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc { + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { db.lookup_intern_type_alias(self) } } From 6d1b4ffa2e18838a6d025b9e38f95dfd4864afa7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 28 Oct 2019 19:08:56 +0100 Subject: [PATCH 054/102] Fix autoimport not choosing the deepest use tree in some situations --- crates/ra_assists/src/assists/add_import.rs | 43 ++++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index e87fae1af0a5..c8b9809f4c85 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -124,9 +124,9 @@ fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) { } } -// Returns the numeber of common segments. +/// Returns the number of common segments. fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize { - left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count() + left.iter().zip(right).take_while(|(l, r)| compare_path_segment(l, r)).count() } fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { @@ -147,7 +147,7 @@ fn compare_path_segment_with_name(a: &SmolStr, b: &ast::Name) -> bool { a == b.text() } -#[derive(Clone)] +#[derive(Clone, Debug)] enum ImportAction { Nothing, // Add a brand new use statement. @@ -217,10 +217,18 @@ impl ImportAction { ( ImportAction::AddNestedImport { common_segments: n, .. }, ImportAction::AddInTreeList { common_segments: m, .. }, - ) => n > m, - ( + ) + | ( ImportAction::AddInTreeList { common_segments: n, .. }, ImportAction::AddNestedImport { common_segments: m, .. }, + ) + | ( + ImportAction::AddInTreeList { common_segments: n, .. }, + ImportAction::AddInTreeList { common_segments: m, .. }, + ) + | ( + ImportAction::AddNestedImport { common_segments: n, .. }, + ImportAction::AddNestedImport { common_segments: m, .. }, ) => n > m, (ImportAction::AddInTreeList { .. }, _) => true, (ImportAction::AddNestedImport { .. }, ImportAction::Nothing) => false, @@ -289,7 +297,7 @@ fn walk_use_tree_for_best_action( common if common == left.len() && left.len() == right.len() => { // e.g: target is std::fmt and we can have // 1- use std::fmt; - // 2- use std::fmt:{ ... } + // 2- use std::fmt::{ ... } if let Some(list) = tree_list { // In case 2 we need to add self to the nested list // unless it's already there @@ -867,6 +875,29 @@ impl Display<|> for Foo { ); } + #[test] + fn test_auto_import_use_nested_import() { + check_assist( + add_import, + " +use crate::{ + ty::{Substs, Ty}, + AssocItem, +}; + +fn foo() { crate::ty::lower<|>::trait_env() } +", + " +use crate::{ + ty::{Substs, Ty, lower}, + AssocItem, +}; + +fn foo() { lower<|>::trait_env() } +", + ); + } + #[test] fn test_auto_import_alias() { check_assist( From 77f90caf2deeb6a2d2c8196399fbba61bf0c461d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 11:15:51 +0300 Subject: [PATCH 055/102] start ra_hir_def crate --- Cargo.lock | 10 ++ crates/ra_hir/Cargo.toml | 1 + crates/ra_hir/src/db.rs | 4 +- crates/ra_hir/src/expr/lower.rs | 11 +-- crates/ra_hir/src/from_source.rs | 4 +- crates/ra_hir/src/ids.rs | 2 +- crates/ra_hir/src/impl_block.rs | 4 +- crates/ra_hir/src/nameres/collector.rs | 13 +-- crates/ra_hir/src/source_id.rs | 132 +++++-------------------- crates/ra_hir_def/Cargo.toml | 10 ++ crates/ra_hir_def/src/ast_id_map.rs | 114 +++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 7 ++ 12 files changed, 181 insertions(+), 131 deletions(-) create mode 100644 crates/ra_hir_def/Cargo.toml create mode 100644 crates/ra_hir_def/src/ast_id_map.rs create mode 100644 crates/ra_hir_def/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0206f16bc3bd..260be7289844 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -991,6 +991,7 @@ dependencies = [ "ra_arena 0.1.0", "ra_cfg 0.1.0", "ra_db 0.1.0", + "ra_hir_def 0.1.0", "ra_mbe 0.1.0", "ra_prof 0.1.0", "ra_syntax 0.1.0", @@ -1000,6 +1001,15 @@ dependencies = [ "test_utils 0.1.0", ] +[[package]] +name = "ra_hir_def" +version = "0.1.0" +dependencies = [ + "ra_arena 0.1.0", + "ra_db 0.1.0", + "ra_syntax 0.1.0", +] + [[package]] name = "ra_ide_api" version = "0.1.0" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index f05ec0b8a730..82720da9e267 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -19,6 +19,7 @@ ra_cfg = { path = "../ra_cfg" } ra_db = { path = "../ra_db" } mbe = { path = "../ra_mbe", package = "ra_mbe" } tt = { path = "../ra_tt", package = "ra_tt" } +hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 489a3b19cabf..7abbf8dca1f7 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -59,11 +59,11 @@ pub trait InternDatabase: SourceDatabase { /// incremental. #[salsa::query_group(AstDatabaseStorage)] pub trait AstDatabase: InternDatabase { - #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)] + #[salsa::invoke(crate::source_id::ast_id_map_query)] fn ast_id_map(&self, file_id: HirFileId) -> Arc; #[salsa::transparent] - #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)] + #[salsa::invoke(crate::source_id::file_item_query)] fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode; #[salsa::transparent] diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 50ea429ea1e6..24733b3de382 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -16,7 +16,7 @@ use crate::{ path::GenericArgs, ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, type_ref::TypeRef, - DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, + AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, Source, }; @@ -458,11 +458,10 @@ where ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::MacroCall(e) => { - let ast_id = self - .db - .ast_id_map(self.current_file_id) - .ast_id(&e) - .with_file_id(self.current_file_id); + let ast_id = AstId::new( + self.current_file_id, + self.db.ast_id_map(self.current_file_id).ast_id(&e), + ); if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index f80d8eb5f1ed..7954c04b2e8b 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -11,7 +11,7 @@ use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, name::AsName, - Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, + AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, }; @@ -183,7 +183,7 @@ impl Module { ModuleSource::Module(ref module) => { assert!(!module.has_semi()); let ast_id_map = db.ast_id_map(src.file_id); - let item_id = ast_id_map.ast_id(module).with_file_id(src.file_id); + let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module)); Some(item_id) } ModuleSource::SourceFile(_) => None, diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 518ea32e99e8..f141206c648d 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -264,7 +264,7 @@ pub(crate) trait AstItemDef: salsa::InternKey + Clone { Self::from_ast_id(ctx, item_id) } fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId) -> Self { - let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) }; + let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; Self::intern(ctx.db, loc) } fn source(self, db: &impl AstDatabase) -> Source { diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 33ef875636d0..9c739f3f166c 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -20,7 +20,7 @@ use crate::{ resolve::Resolver, ty::Ty, type_ref::TypeRef, - AssocItem, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, + AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, TypeAlias, }; @@ -256,7 +256,7 @@ impl ModuleImplBlocks { } //FIXME: we should really cut down on the boilerplate required to process a macro - let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); + let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_call)); if let Some(path) = macro_call .path() .and_then(|path| Path::from_src(Source { ast: path, file_id }, db)) diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index b5fe16bfa4d4..4f363df36918 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -567,7 +567,7 @@ where // inline module, just recurse raw::ModuleData::Definition { name, items, ast_id } => { let module_id = - self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); + self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None); ModCollector { def_collector: &mut *self.def_collector, @@ -583,7 +583,7 @@ where } // out of line module, resolve, parse and recurse raw::ModuleData::Declaration { name, ast_id } => { - let ast_id = ast_id.with_file_id(self.file_id); + let ast_id = AstId::new(self.file_id, *ast_id); match self.mod_dir.resolve_declaration( self.def_collector.db, self.file_id, @@ -671,21 +671,18 @@ where } fn collect_macro(&mut self, mac: &raw::MacroData) { + let ast_id = AstId::new(self.file_id, mac.ast_id); + // Case 1: macro rules, define a macro in crate-global mutable scope if is_macro_rules(&mac.path) { if let Some(name) = &mac.name { - let macro_id = MacroDefId { - ast_id: mac.ast_id.with_file_id(self.file_id), - krate: self.def_collector.def_map.krate, - }; + let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate }; let macro_ = MacroDef { id: macro_id }; self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); } return; } - let ast_id = mac.ast_id.with_file_id(self.file_id); - // Case 2: try to resolve in legacy scope and expand macro_rules, triggering // recursive item collection. if let Some(macro_def) = mac.path.as_ident().and_then(|name| { diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index a4dd99598c58..260b7966106b 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -2,18 +2,18 @@ use std::{ hash::{Hash, Hasher}, - marker::PhantomData, sync::Arc, }; -use ra_arena::{impl_arena_id, Arena, RawId}; -use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; +pub use hir_def::ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}; +use ra_syntax::{AstNode, SyntaxNode}; use crate::{db::AstDatabase, HirFileId}; /// `AstId` points to an AST node in any file. /// /// It is stable across reparses, and can be used as salsa key/value. +// FIXME: isn't this just a `Source>` ? #[derive(Debug)] pub(crate) struct AstId { file_id: HirFileId, @@ -40,122 +40,34 @@ impl Hash for AstId { } impl AstId { + pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { + AstId { file_id, file_ast_id } + } + pub(crate) fn file_id(&self) -> HirFileId { self.file_id } pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N { - let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw); + let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); N::cast(syntax_node).unwrap() } } -/// `AstId` points to an AST node in a specific file. -#[derive(Debug)] -pub(crate) struct FileAstId { - raw: ErasedFileAstId, - _ty: PhantomData N>, +pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc { + let map = if let Some(node) = db.parse_or_expand(file_id) { + AstIdMap::from_source(&node) + } else { + AstIdMap::default() + }; + Arc::new(map) } -impl Clone for FileAstId { - fn clone(&self) -> FileAstId { - *self - } -} -impl Copy for FileAstId {} - -impl PartialEq for FileAstId { - fn eq(&self, other: &Self) -> bool { - self.raw == other.raw - } -} -impl Eq for FileAstId {} -impl Hash for FileAstId { - fn hash(&self, hasher: &mut H) { - self.raw.hash(hasher); - } -} - -impl FileAstId { - pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId { - AstId { file_id, file_ast_id: self } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ErasedFileAstId(RawId); -impl_arena_id!(ErasedFileAstId); - -/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. -#[derive(Debug, PartialEq, Eq, Default)] -pub struct AstIdMap { - arena: Arena, -} - -impl AstIdMap { - pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc { - let map = if let Some(node) = db.parse_or_expand(file_id) { - AstIdMap::from_source(&node) - } else { - AstIdMap::default() - }; - Arc::new(map) - } - - pub(crate) fn file_item_query( - db: &impl AstDatabase, - file_id: HirFileId, - ast_id: ErasedFileAstId, - ) -> SyntaxNode { - let node = db.parse_or_expand(file_id).unwrap(); - db.ast_id_map(file_id).arena[ast_id].to_node(&node) - } - - pub(crate) fn ast_id(&self, item: &N) -> FileAstId { - let ptr = SyntaxNodePtr::new(item.syntax()); - let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) { - Some((it, _)) => it, - None => panic!( - "Can't find {:?} in AstIdMap:\n{:?}", - item.syntax(), - self.arena.iter().map(|(_id, i)| i).collect::>(), - ), - }; - - FileAstId { raw, _ty: PhantomData } - } - - fn from_source(node: &SyntaxNode) -> AstIdMap { - assert!(node.parent().is_none()); - let mut res = AstIdMap { arena: Arena::default() }; - // By walking the tree in bread-first order we make sure that parents - // get lower ids then children. That is, adding a new child does not - // change parent's id. This means that, say, adding a new function to a - // trait does not change ids of top-level items, which helps caching. - bfs(node, |it| { - if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { - res.alloc(module_item.syntax()); - } else if let Some(macro_call) = ast::MacroCall::cast(it) { - res.alloc(macro_call.syntax()); - } - }); - res - } - - fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { - self.arena.alloc(SyntaxNodePtr::new(item)) - } -} - -/// Walks the subtree in bfs order, calling `f` for each node. -fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { - let mut curr_layer = vec![node.clone()]; - let mut next_layer = vec![]; - while !curr_layer.is_empty() { - curr_layer.drain(..).for_each(|node| { - next_layer.extend(node.children()); - f(node); - }); - std::mem::swap(&mut curr_layer, &mut next_layer); - } +pub(crate) fn file_item_query( + db: &impl AstDatabase, + file_id: HirFileId, + ast_id: ErasedFileAstId, +) -> SyntaxNode { + let node = db.parse_or_expand(file_id).unwrap(); + db.ast_id_map(file_id)[ast_id].to_node(&node) } diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml new file mode 100644 index 000000000000..7c57d56bd486 --- /dev/null +++ b/crates/ra_hir_def/Cargo.toml @@ -0,0 +1,10 @@ +[package] +edition = "2018" +name = "ra_hir_def" +version = "0.1.0" +authors = ["rust-analyzer developers"] + +[dependencies] +ra_arena = { path = "../ra_arena" } +ra_db = { path = "../ra_db" } +ra_syntax = { path = "../ra_syntax" } diff --git a/crates/ra_hir_def/src/ast_id_map.rs b/crates/ra_hir_def/src/ast_id_map.rs new file mode 100644 index 000000000000..c3b389102ac5 --- /dev/null +++ b/crates/ra_hir_def/src/ast_id_map.rs @@ -0,0 +1,114 @@ +//! `AstIdMap` allows to create stable IDs for "large" syntax nodes like items +//! and macro calls. +//! +//! Specifically, it enumerates all items in a file and uses position of a an +//! item as an ID. That way, id's don't change unless the set of items itself +//! changes. + +use std::{ + hash::{Hash, Hasher}, + marker::PhantomData, + ops, +}; + +use ra_arena::{impl_arena_id, Arena, RawId}; +use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; + +/// `AstId` points to an AST node in a specific file. +#[derive(Debug)] +pub struct FileAstId { + raw: ErasedFileAstId, + _ty: PhantomData N>, +} + +impl Clone for FileAstId { + fn clone(&self) -> FileAstId { + *self + } +} +impl Copy for FileAstId {} + +impl PartialEq for FileAstId { + fn eq(&self, other: &Self) -> bool { + self.raw == other.raw + } +} +impl Eq for FileAstId {} +impl Hash for FileAstId { + fn hash(&self, hasher: &mut H) { + self.raw.hash(hasher); + } +} + +impl From> for ErasedFileAstId { + fn from(id: FileAstId) -> Self { + id.raw + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ErasedFileAstId(RawId); +impl_arena_id!(ErasedFileAstId); + +/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. +#[derive(Debug, PartialEq, Eq, Default)] +pub struct AstIdMap { + arena: Arena, +} + +impl AstIdMap { + pub fn from_source(node: &SyntaxNode) -> AstIdMap { + assert!(node.parent().is_none()); + let mut res = AstIdMap { arena: Arena::default() }; + // By walking the tree in bread-first order we make sure that parents + // get lower ids then children. That is, adding a new child does not + // change parent's id. This means that, say, adding a new function to a + // trait does not change ids of top-level items, which helps caching. + bfs(node, |it| { + if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { + res.alloc(module_item.syntax()); + } else if let Some(macro_call) = ast::MacroCall::cast(it) { + res.alloc(macro_call.syntax()); + } + }); + res + } + + pub fn ast_id(&self, item: &N) -> FileAstId { + let ptr = SyntaxNodePtr::new(item.syntax()); + let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) { + Some((it, _)) => it, + None => panic!( + "Can't find {:?} in AstIdMap:\n{:?}", + item.syntax(), + self.arena.iter().map(|(_id, i)| i).collect::>(), + ), + }; + + FileAstId { raw, _ty: PhantomData } + } + + fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { + self.arena.alloc(SyntaxNodePtr::new(item)) + } +} + +impl ops::Index for AstIdMap { + type Output = SyntaxNodePtr; + fn index(&self, index: ErasedFileAstId) -> &SyntaxNodePtr { + &self.arena[index] + } +} + +/// Walks the subtree in bfs order, calling `f` for each node. +fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { + let mut curr_layer = vec![node.clone()]; + let mut next_layer = vec![]; + while !curr_layer.is_empty() { + curr_layer.drain(..).for_each(|node| { + next_layer.extend(node.children()); + f(node); + }); + std::mem::swap(&mut curr_layer, &mut next_layer); + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs new file mode 100644 index 000000000000..4d4d2cb19c74 --- /dev/null +++ b/crates/ra_hir_def/src/lib.rs @@ -0,0 +1,7 @@ +//! `ra_hir_def` contains initial "phases" of the compiler. Roughly, everything +//! before types. +//! +//! Note that we are in the process of moving parts of `ra_hir` into +//! `ra_hir_def`, so this crates doesn't contain a lot at the moment. + +pub mod ast_id_map; From 541387564483ee3a42a1969fd048f94e57599ca4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 14:55:39 +0300 Subject: [PATCH 056/102] move expansion-related code to a separate crate --- Cargo.lock | 4 + crates/ra_hir/src/db.rs | 44 +---- crates/ra_hir/src/debug.rs | 10 +- crates/ra_hir/src/ids.rs | 206 ++------------------- crates/ra_hir/src/nameres/collector.rs | 3 +- crates/ra_hir/src/path.rs | 9 +- crates/ra_hir/src/source_id.rs | 73 +------- crates/ra_hir_def/Cargo.toml | 5 + crates/ra_hir_def/src/db.rs | 46 +++++ crates/ra_hir_def/src/expand.rs | 243 +++++++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 4 + 11 files changed, 344 insertions(+), 303 deletions(-) create mode 100644 crates/ra_hir_def/src/db.rs create mode 100644 crates/ra_hir_def/src/expand.rs diff --git a/Cargo.lock b/Cargo.lock index 260be7289844..c0b060aeafc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,9 +1005,13 @@ dependencies = [ name = "ra_hir_def" version = "0.1.0" dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", "ra_db 0.1.0", + "ra_mbe 0.1.0", + "ra_prof 0.1.0", "ra_syntax 0.1.0", + "ra_tt 0.1.0", ] [[package]] diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 7abbf8dca1f7..a8fd695c0d2f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use ra_db::{salsa, SourceDatabase}; -use ra_syntax::{ast, Parse, SmolStr, SyntaxNode}; +use ra_syntax::{ast, SmolStr}; use crate::{ adt::{EnumData, StructData}, @@ -19,9 +19,13 @@ use crate::{ InferenceResult, Substs, Ty, TypableDef, TypeCtor, }, type_alias::TypeAliasData, - AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData, - Function, HirFileId, MacroCallLoc, MacroDefId, Module, Static, Struct, StructField, Trait, - TypeAlias, + Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, HirFileId, Module, + Static, Struct, StructField, Trait, TypeAlias, +}; + +pub use hir_def::db::{ + AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, + ParseMacroQuery, }; /// We store all interned things in the single QueryGroup. @@ -31,8 +35,6 @@ use crate::{ /// two. #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { - #[salsa::interned] - fn intern_macro(&self, macro_call: MacroCallLoc) -> ids::MacroCallId; #[salsa::interned] fn intern_function(&self, loc: ids::ItemLoc) -> ids::FunctionId; #[salsa::interned] @@ -55,38 +57,10 @@ pub trait InternDatabase: SourceDatabase { fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; } -/// This database has access to source code, so queries here are not really -/// incremental. -#[salsa::query_group(AstDatabaseStorage)] -pub trait AstDatabase: InternDatabase { - #[salsa::invoke(crate::source_id::ast_id_map_query)] - fn ast_id_map(&self, file_id: HirFileId) -> Arc; - - #[salsa::transparent] - #[salsa::invoke(crate::source_id::file_item_query)] - fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode; - - #[salsa::transparent] - #[salsa::invoke(crate::ids::HirFileId::parse_or_expand_query)] - fn parse_or_expand(&self, file_id: HirFileId) -> Option; - - #[salsa::invoke(crate::ids::HirFileId::parse_macro_query)] - fn parse_macro(&self, macro_file: ids::MacroFile) -> Option>; - - #[salsa::invoke(crate::ids::macro_def_query)] - fn macro_def(&self, macro_id: MacroDefId) -> Option>; - - #[salsa::invoke(crate::ids::macro_arg_query)] - fn macro_arg(&self, macro_call: ids::MacroCallId) -> Option>; - - #[salsa::invoke(crate::ids::macro_expand_query)] - fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result, String>; -} - // This database uses `AstDatabase` internally, #[salsa::query_group(DefDatabaseStorage)] #[salsa::requires(AstDatabase)] -pub trait DefDatabase: InternDatabase + HirDebugDatabase { +pub trait DefDatabase: InternDatabase + HirDebugDatabase + AstDatabase { #[salsa::invoke(crate::adt::StructData::struct_data_query)] fn struct_data(&self, s: Struct) -> Arc; diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs index 48b69000bcdc..c3f890ed4a1a 100644 --- a/crates/ra_hir/src/debug.rs +++ b/crates/ra_hir/src/debug.rs @@ -36,11 +36,11 @@ impl Module { } } -impl HirFileId { - pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ { - debug_fn(move |fmt| db.debug_hir_file_id(self, fmt)) - } -} +// impl HirFileId { +// pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ { +// debug_fn(move |fmt| db.debug_hir_file_id(self, fmt)) +// } +// } pub trait HirDebugHelper: HirDatabase { fn crate_name(&self, _krate: CrateId) -> Option { diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index f141206c648d..9f85bb30d2ec 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -1,168 +1,23 @@ -//! FIXME: write short doc here +//! hir makes heavy use of ids: integer (u32) handlers to various things. You +//! can think of id as a pointer (but without a lifetime) or a file descriptor +//! (but for hir objects). +//! +//! This module defines a bunch of ids we are using. The most important ones are +//! probably `HirFileId` and `DefId`. -use std::{ - hash::{Hash, Hasher}, - sync::Arc, -}; +use std::hash::{Hash, Hasher}; -use mbe::MacroRules; -use ra_db::{salsa, FileId}; -use ra_prof::profile; -use ra_syntax::{ast, AstNode, Parse, SyntaxNode}; +use ra_db::salsa; +use ra_syntax::{ast, AstNode}; use crate::{ db::{AstDatabase, InternDatabase}, - AstId, Crate, FileAstId, Module, Source, + AstId, FileAstId, Module, Source, }; -/// hir makes heavy use of ids: integer (u32) handlers to various things. You -/// can think of id as a pointer (but without a lifetime) or a file descriptor -/// (but for hir objects). -/// -/// This module defines a bunch of ids we are using. The most important ones are -/// probably `HirFileId` and `DefId`. - -/// Input to the analyzer is a set of files, where each file is identified by -/// `FileId` and contains source code. However, another source of source code in -/// Rust are macros: each macro can be thought of as producing a "temporary -/// file". To assign an id to such a file, we use the id of the macro call that -/// produced the file. So, a `HirFileId` is either a `FileId` (source code -/// written by user), or a `MacroCallId` (source code produced by macro). -/// -/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file -/// containing the call plus the offset of the macro call in the file. Note that -/// this is a recursive definition! However, the size_of of `HirFileId` is -/// finite (because everything bottoms out at the real `FileId`) and small -/// (`MacroCallId` uses the location interner). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HirFileId(HirFileIdRepr); - -impl HirFileId { - /// For macro-expansion files, returns the file original source file the - /// expansion originated from. - pub fn original_file(self, db: &impl InternDatabase) -> FileId { - match self.0 { - HirFileIdRepr::File(file_id) => file_id, - HirFileIdRepr::Macro(macro_file) => { - let loc = macro_file.macro_call_id.loc(db); - loc.ast_id.file_id().original_file(db) - } - } - } - - /// Get the crate which the macro lives in, if it is a macro file. - pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::File(_) => None, - HirFileIdRepr::Macro(macro_file) => { - let loc = macro_file.macro_call_id.loc(db); - Some(loc.def.krate) - } - } - } - - pub(crate) fn parse_or_expand_query( - db: &impl AstDatabase, - file_id: HirFileId, - ) -> Option { - match file_id.0 { - HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()), - HirFileIdRepr::Macro(macro_file) => { - db.parse_macro(macro_file).map(|it| it.syntax_node()) - } - } - } - - pub(crate) fn parse_macro_query( - db: &impl AstDatabase, - macro_file: MacroFile, - ) -> Option> { - let _p = profile("parse_macro_query"); - let macro_call_id = macro_file.macro_call_id; - let tt = db - .macro_expand(macro_call_id) - .map_err(|err| { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - log::warn!("fail on macro_parse: (reason: {})", err,); - }) - .ok()?; - match macro_file.macro_file_kind { - MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), - MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum HirFileIdRepr { - File(FileId), - Macro(MacroFile), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroFile { - macro_call_id: MacroCallId, - macro_file_kind: MacroFileKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum MacroFileKind { - Items, - Expr, -} - -impl From for HirFileId { - fn from(file_id: FileId) -> HirFileId { - HirFileId(HirFileIdRepr::File(file_id)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroDefId { - pub(crate) ast_id: AstId, - pub(crate) krate: Crate, -} - -pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option> { - let macro_call = id.ast_id.to_node(db); - let arg = macro_call.token_tree()?; - let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { - log::warn!("fail on macro_def to token tree: {:#?}", arg); - None - })?; - let rules = MacroRules::parse(&tt).ok().or_else(|| { - log::warn!("fail on macro_def parse: {:#?}", tt); - None - })?; - Some(Arc::new(rules)) -} - -pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option> { - let loc = id.loc(db); - let macro_call = loc.ast_id.to_node(db); - let arg = macro_call.token_tree()?; - let (tt, _) = mbe::ast_to_token_tree(&arg)?; - Some(Arc::new(tt)) -} - -pub(crate) fn macro_expand_query( - db: &impl AstDatabase, - id: MacroCallId, -) -> Result, String> { - let loc = id.loc(db); - let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; - - let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; - let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; - // Set a hard limit for the expanded tt - let count = tt.count(); - if count > 65536 { - return Err(format!("Total tokens count exceed limit : count = {}", count)); - } - Ok(Arc::new(tt)) -} +pub use hir_def::expand::{ + HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, +}; macro_rules! impl_intern_key { ($name:ident) => { @@ -177,35 +32,6 @@ macro_rules! impl_intern_key { }; } -/// `MacroCallId` identifies a particular macro invocation, like -/// `println!("Hello, {}", world)`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroCallId(salsa::InternId); -impl_intern_key!(MacroCallId); - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroCallLoc { - pub(crate) def: MacroDefId, - pub(crate) ast_id: AstId, -} - -impl MacroCallId { - pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc { - db.lookup_intern_macro(self) - } - - pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId { - let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; - HirFileId(HirFileIdRepr::Macro(macro_file)) - } -} - -impl MacroCallLoc { - pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId { - db.intern_macro(self) - } -} - #[derive(Debug)] pub struct ItemLoc { pub(crate) module: Module, @@ -244,7 +70,7 @@ impl<'a, DB> LocationCtx<&'a DB> { } } -impl<'a, DB: AstDatabase> LocationCtx<&'a DB> { +impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> { pub(crate) fn to_def(self, ast: &N) -> DEF where N: AstNode, @@ -258,7 +84,7 @@ pub(crate) trait AstItemDef: salsa::InternKey + Clone { fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self; fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc; - fn from_ast(ctx: LocationCtx<&impl AstDatabase>, ast: &N) -> Self { + fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self { let items = ctx.db.ast_id_map(ctx.file_id); let item_id = items.ast_id(ast); Self::from_ast_id(ctx, item_id) @@ -267,7 +93,7 @@ pub(crate) trait AstItemDef: salsa::InternKey + Clone { let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; Self::intern(ctx.db, loc) } - fn source(self, db: &impl AstDatabase) -> Source { + fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source { let loc = self.lookup_intern(db); let ast = loc.ast_id.to_node(db); Source { file_id: loc.ast_id.file_id(), ast } diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 4f363df36918..885ea57a1c56 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -676,7 +676,8 @@ where // Case 1: macro rules, define a macro in crate-global mutable scope if is_macro_rules(&mac.path) { if let Some(name) = &mac.name { - let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate }; + let macro_id = + MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id }; let macro_ = MacroDef { id: macro_id }; self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); } diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 394617e1a4c0..bbe536bcb4a9 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -66,7 +66,12 @@ impl Path { mut cb: impl FnMut(Path, &ast::UseTree, bool, Option), ) { if let Some(tree) = item_src.ast.use_tree() { - expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); + expand_use_tree( + None, + tree, + &|| item_src.file_id.macro_crate(db).map(|crate_id| Crate { crate_id }), + &mut cb, + ); } } @@ -90,7 +95,7 @@ impl Path { /// It correctly handles `$crate` based path from macro call. pub fn from_src(source: Source, db: &impl AstDatabase) -> Option { let file_id = source.file_id; - Path::parse(source.ast, &|| file_id.macro_crate(db)) + Path::parse(source.ast, &|| file_id.macro_crate(db).map(|crate_id| Crate { crate_id })) } fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option) -> Option { diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index 260b7966106b..c70245949ba3 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -1,73 +1,6 @@ //! FIXME: write short doc here -use std::{ - hash::{Hash, Hasher}, - sync::Arc, +pub use hir_def::{ + ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}, + expand::AstId, }; - -pub use hir_def::ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}; -use ra_syntax::{AstNode, SyntaxNode}; - -use crate::{db::AstDatabase, HirFileId}; - -/// `AstId` points to an AST node in any file. -/// -/// It is stable across reparses, and can be used as salsa key/value. -// FIXME: isn't this just a `Source>` ? -#[derive(Debug)] -pub(crate) struct AstId { - file_id: HirFileId, - file_ast_id: FileAstId, -} - -impl Clone for AstId { - fn clone(&self) -> AstId { - *self - } -} -impl Copy for AstId {} - -impl PartialEq for AstId { - fn eq(&self, other: &Self) -> bool { - (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id) - } -} -impl Eq for AstId {} -impl Hash for AstId { - fn hash(&self, hasher: &mut H) { - (self.file_id, self.file_ast_id).hash(hasher); - } -} - -impl AstId { - pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { - AstId { file_id, file_ast_id } - } - - pub(crate) fn file_id(&self) -> HirFileId { - self.file_id - } - - pub(crate) fn to_node(&self, db: &impl AstDatabase) -> N { - let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); - N::cast(syntax_node).unwrap() - } -} - -pub(crate) fn ast_id_map_query(db: &impl AstDatabase, file_id: HirFileId) -> Arc { - let map = if let Some(node) = db.parse_or_expand(file_id) { - AstIdMap::from_source(&node) - } else { - AstIdMap::default() - }; - Arc::new(map) -} - -pub(crate) fn file_item_query( - db: &impl AstDatabase, - file_id: HirFileId, - ast_id: ErasedFileAstId, -) -> SyntaxNode { - let node = db.parse_or_expand(file_id).unwrap(); - db.ast_id_map(file_id)[ast_id].to_node(&node) -} diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 7c57d56bd486..049f8a4fc690 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -5,6 +5,11 @@ version = "0.1.0" authors = ["rust-analyzer developers"] [dependencies] +log = "0.4.5" + ra_arena = { path = "../ra_arena" } ra_db = { path = "../ra_db" } ra_syntax = { path = "../ra_syntax" } +ra_prof = { path = "../ra_prof" } +tt = { path = "../ra_tt", package = "ra_tt" } +mbe = { path = "../ra_mbe", package = "ra_mbe" } diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs new file mode 100644 index 000000000000..7133b61dba5d --- /dev/null +++ b/crates/ra_hir_def/src/db.rs @@ -0,0 +1,46 @@ +use std::sync::Arc; + +use ra_db::{salsa, SourceDatabase}; +use ra_syntax::{Parse, SyntaxNode}; + +use crate::{ + ast_id_map::{AstIdMap, ErasedFileAstId}, + expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, +}; + +#[salsa::query_group(AstDatabaseStorage)] +pub trait AstDatabase: SourceDatabase { + fn ast_id_map(&self, file_id: HirFileId) -> Arc; + #[salsa::transparent] + fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode; + + #[salsa::transparent] + #[salsa::invoke(crate::expand::parse_or_expand_query)] + fn parse_or_expand(&self, file_id: HirFileId) -> Option; + + #[salsa::interned] + fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; + #[salsa::invoke(crate::expand::macro_arg_query)] + fn macro_arg(&self, id: MacroCallId) -> Option>; + #[salsa::invoke(crate::expand::macro_def_query)] + fn macro_def(&self, id: MacroDefId) -> Option>; + #[salsa::invoke(crate::expand::parse_macro_query)] + fn parse_macro(&self, macro_file: MacroFile) -> Option>; + #[salsa::invoke(crate::expand::macro_expand_query)] + fn macro_expand(&self, macro_call: MacroCallId) -> Result, String>; +} + +pub(crate) fn ast_id_map(db: &impl AstDatabase, file_id: HirFileId) -> Arc { + let map = + db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it)); + Arc::new(map) +} + +pub(crate) fn ast_id_to_node( + db: &impl AstDatabase, + file_id: HirFileId, + ast_id: ErasedFileAstId, +) -> SyntaxNode { + let node = db.parse_or_expand(file_id).unwrap(); + db.ast_id_map(file_id)[ast_id].to_node(&node) +} diff --git a/crates/ra_hir_def/src/expand.rs b/crates/ra_hir_def/src/expand.rs new file mode 100644 index 000000000000..6517ea84da70 --- /dev/null +++ b/crates/ra_hir_def/src/expand.rs @@ -0,0 +1,243 @@ +use std::{ + hash::{Hash, Hasher}, + sync::Arc, +}; + +use mbe::MacroRules; +use ra_db::{salsa, CrateId, FileId}; +use ra_prof::profile; +use ra_syntax::{ + ast::{self, AstNode}, + Parse, SyntaxNode, +}; + +use crate::{ast_id_map::FileAstId, db::AstDatabase}; + +macro_rules! impl_intern_key { + ($name:ident) => { + impl salsa::InternKey for $name { + fn from_intern_id(v: salsa::InternId) -> Self { + $name(v) + } + fn as_intern_id(&self) -> salsa::InternId { + self.0 + } + } + }; +} + +/// Input to the analyzer is a set of files, where each file is identified by +/// `FileId` and contains source code. However, another source of source code in +/// Rust are macros: each macro can be thought of as producing a "temporary +/// file". To assign an id to such a file, we use the id of the macro call that +/// produced the file. So, a `HirFileId` is either a `FileId` (source code +/// written by user), or a `MacroCallId` (source code produced by macro). +/// +/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file +/// containing the call plus the offset of the macro call in the file. Note that +/// this is a recursive definition! However, the size_of of `HirFileId` is +/// finite (because everything bottoms out at the real `FileId`) and small +/// (`MacroCallId` uses the location interner). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum HirFileId { + FileId(FileId), + MacroFile(MacroFile), +} + +impl From for HirFileId { + fn from(id: FileId) -> Self { + HirFileId::FileId(id) + } +} + +impl From for HirFileId { + fn from(id: MacroFile) -> Self { + HirFileId::MacroFile(id) + } +} + +impl HirFileId { + /// For macro-expansion files, returns the file original source file the + /// expansion originated from. + pub fn original_file(self, db: &impl AstDatabase) -> FileId { + match self { + HirFileId::FileId(file_id) => file_id, + HirFileId::MacroFile(macro_file) => { + let loc = db.lookup_intern_macro(macro_file.macro_call_id); + loc.ast_id.file_id().original_file(db) + } + } + } + + /// Get the crate which the macro lives in, if it is a macro file. + pub fn macro_crate(self, db: &impl AstDatabase) -> Option { + match self { + HirFileId::FileId(_) => None, + HirFileId::MacroFile(macro_file) => { + let loc = db.lookup_intern_macro(macro_file.macro_call_id); + Some(loc.def.krate) + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroFile { + macro_call_id: MacroCallId, + macro_file_kind: MacroFileKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MacroFileKind { + Items, + Expr, +} + +/// `MacroCallId` identifies a particular macro invocation, like +/// `println!("Hello, {}", world)`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroCallId(salsa::InternId); +impl_intern_key!(MacroCallId); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroDefId { + pub krate: CrateId, + pub ast_id: AstId, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroCallLoc { + pub def: MacroDefId, + pub ast_id: AstId, +} + +impl MacroCallId { + pub fn loc(self, db: &impl AstDatabase) -> MacroCallLoc { + db.lookup_intern_macro(self) + } + + pub fn as_file(self, kind: MacroFileKind) -> HirFileId { + let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; + macro_file.into() + } +} + +impl MacroCallLoc { + pub fn id(self, db: &impl AstDatabase) -> MacroCallId { + db.intern_macro(self) + } +} + +/// `AstId` points to an AST node in any file. +/// +/// It is stable across reparses, and can be used as salsa key/value. +// FIXME: isn't this just a `Source>` ? +#[derive(Debug)] +pub struct AstId { + file_id: HirFileId, + file_ast_id: FileAstId, +} + +impl Clone for AstId { + fn clone(&self) -> AstId { + *self + } +} +impl Copy for AstId {} + +impl PartialEq for AstId { + fn eq(&self, other: &Self) -> bool { + (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id) + } +} +impl Eq for AstId {} +impl Hash for AstId { + fn hash(&self, hasher: &mut H) { + (self.file_id, self.file_ast_id).hash(hasher); + } +} + +impl AstId { + pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { + AstId { file_id, file_ast_id } + } + + pub fn file_id(&self) -> HirFileId { + self.file_id + } + + pub fn to_node(&self, db: &impl AstDatabase) -> N { + let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); + N::cast(syntax_node).unwrap() + } +} + +pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option> { + let macro_call = id.ast_id.to_node(db); + let arg = macro_call.token_tree()?; + let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { + log::warn!("fail on macro_def to token tree: {:#?}", arg); + None + })?; + let rules = MacroRules::parse(&tt).ok().or_else(|| { + log::warn!("fail on macro_def parse: {:#?}", tt); + None + })?; + Some(Arc::new(rules)) +} + +pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option> { + let loc = db.lookup_intern_macro(id); + let macro_call = loc.ast_id.to_node(db); + let arg = macro_call.token_tree()?; + let (tt, _) = mbe::ast_to_token_tree(&arg)?; + Some(Arc::new(tt)) +} + +pub(crate) fn macro_expand_query( + db: &impl AstDatabase, + id: MacroCallId, +) -> Result, String> { + let loc = db.lookup_intern_macro(id); + let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; + + let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; + let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; + // Set a hard limit for the expanded tt + let count = tt.count(); + if count > 65536 { + return Err(format!("Total tokens count exceed limit : count = {}", count)); + } + Ok(Arc::new(tt)) +} + +pub(crate) fn parse_or_expand_query( + db: &impl AstDatabase, + file_id: HirFileId, +) -> Option { + match file_id { + HirFileId::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), + HirFileId::MacroFile(macro_file) => db.parse_macro(macro_file).map(|it| it.syntax_node()), + } +} + +pub(crate) fn parse_macro_query( + db: &impl AstDatabase, + macro_file: MacroFile, +) -> Option> { + let _p = profile("parse_macro_query"); + let macro_call_id = macro_file.macro_call_id; + let tt = db + .macro_expand(macro_call_id) + .map_err(|err| { + // Note: + // The final goal we would like to make all parse_macro success, + // such that the following log will not call anyway. + log::warn!("fail on macro_parse: (reason: {})", err,); + }) + .ok()?; + match macro_file.macro_file_kind { + MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), + MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 4d4d2cb19c74..6ccb11068127 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -4,4 +4,8 @@ //! Note that we are in the process of moving parts of `ra_hir` into //! `ra_hir_def`, so this crates doesn't contain a lot at the moment. +pub mod db; + pub mod ast_id_map; + +pub mod expand; From 5b803055b7b690a57f1c08da8f1640139c739e76 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 14:59:55 +0300 Subject: [PATCH 057/102] rename hir_def -> hir_expand --- Cargo.lock | 4 ++-- crates/ra_hir/Cargo.toml | 2 +- crates/ra_hir/src/db.rs | 2 +- crates/ra_hir/src/ids.rs | 2 +- crates/ra_hir/src/source_id.rs | 2 +- crates/{ra_hir_def => ra_hir_expand}/Cargo.toml | 2 +- crates/{ra_hir_def => ra_hir_expand}/src/ast_id_map.rs | 0 crates/{ra_hir_def => ra_hir_expand}/src/db.rs | 0 crates/{ra_hir_def => ra_hir_expand}/src/expand.rs | 0 crates/{ra_hir_def => ra_hir_expand}/src/lib.rs | 0 10 files changed, 7 insertions(+), 7 deletions(-) rename crates/{ra_hir_def => ra_hir_expand}/Cargo.toml (93%) rename crates/{ra_hir_def => ra_hir_expand}/src/ast_id_map.rs (100%) rename crates/{ra_hir_def => ra_hir_expand}/src/db.rs (100%) rename crates/{ra_hir_def => ra_hir_expand}/src/expand.rs (100%) rename crates/{ra_hir_def => ra_hir_expand}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index c0b060aeafc7..6a335689439d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -991,7 +991,7 @@ dependencies = [ "ra_arena 0.1.0", "ra_cfg 0.1.0", "ra_db 0.1.0", - "ra_hir_def 0.1.0", + "ra_hir_expand 0.1.0", "ra_mbe 0.1.0", "ra_prof 0.1.0", "ra_syntax 0.1.0", @@ -1002,7 +1002,7 @@ dependencies = [ ] [[package]] -name = "ra_hir_def" +name = "ra_hir_expand" version = "0.1.0" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 82720da9e267..2090f3b20791 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -19,7 +19,7 @@ ra_cfg = { path = "../ra_cfg" } ra_db = { path = "../ra_db" } mbe = { path = "../ra_mbe", package = "ra_mbe" } tt = { path = "../ra_tt", package = "ra_tt" } -hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } +hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index a8fd695c0d2f..6d34c671dce3 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -23,7 +23,7 @@ use crate::{ Static, Struct, StructField, Trait, TypeAlias, }; -pub use hir_def::db::{ +pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, }; diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 9f85bb30d2ec..eb2d2340991a 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -15,7 +15,7 @@ use crate::{ AstId, FileAstId, Module, Source, }; -pub use hir_def::expand::{ +pub use hir_expand::expand::{ HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, }; diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index c70245949ba3..b37474418fd7 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -pub use hir_def::{ +pub use hir_expand::{ ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}, expand::AstId, }; diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_expand/Cargo.toml similarity index 93% rename from crates/ra_hir_def/Cargo.toml rename to crates/ra_hir_expand/Cargo.toml index 049f8a4fc690..9bf5b7918751 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2018" -name = "ra_hir_def" +name = "ra_hir_expand" version = "0.1.0" authors = ["rust-analyzer developers"] diff --git a/crates/ra_hir_def/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs similarity index 100% rename from crates/ra_hir_def/src/ast_id_map.rs rename to crates/ra_hir_expand/src/ast_id_map.rs diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_expand/src/db.rs similarity index 100% rename from crates/ra_hir_def/src/db.rs rename to crates/ra_hir_expand/src/db.rs diff --git a/crates/ra_hir_def/src/expand.rs b/crates/ra_hir_expand/src/expand.rs similarity index 100% rename from crates/ra_hir_def/src/expand.rs rename to crates/ra_hir_expand/src/expand.rs diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_expand/src/lib.rs similarity index 100% rename from crates/ra_hir_def/src/lib.rs rename to crates/ra_hir_expand/src/lib.rs From 632a22ae621079beaee6bbb155997e763c6b068d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 29 Oct 2019 13:01:33 +0100 Subject: [PATCH 058/102] Upgrade Chalk, make use of TypeName::Error variant --- Cargo.lock | 59 +++++++++++++++++----------- crates/ra_hir/Cargo.toml | 6 +-- crates/ra_hir/src/ty/traits/chalk.rs | 15 ++++--- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 260be7289844..ff3362be99ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,12 +123,22 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chalk-derive" +version = "0.1.0" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "chalk-engine" version = "0.9.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" dependencies = [ - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -136,17 +146,18 @@ dependencies = [ [[package]] name = "chalk-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "chalk-macros" version = "0.1.1" -source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -154,22 +165,23 @@ dependencies = [ [[package]] name = "chalk-rust-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", ] [[package]] name = "chalk-solve" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae#1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" +source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -979,9 +991,9 @@ name = "ra_hir" version = "0.1.0" dependencies = [ "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", - "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1804,11 +1816,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" -"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" -"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" -"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" -"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae)" = "" +"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 82720da9e267..67f8c4946ca0 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -23,9 +23,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "1e5c1929364dfbb7c0c7ac0956b8250abe7c2cae" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } lalrpop-intern = "0.15.1" [dev-dependencies] diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index ad7c11a5a83d..e18c28cf6386 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -66,13 +66,11 @@ impl ToChalk for Ty { } Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), - // FIXME this is clearly incorrect, but probably not too incorrect - // and I'm not sure what to actually do with Ty::Unknown - // maybe an alternative would be `for T`? (meaningless in rust, but expressible in chalk's Ty) // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { - PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() } - .to_ty::() + let parameters = Vec::new(); + let name = TypeName::Error; + chalk_ir::ApplicationTy { name, parameters }.cast() } } } @@ -92,6 +90,7 @@ impl ToChalk for Ty { let parameters = from_chalk(db, apply_ty.parameters); Ty::Apply(ApplicationTy { ctor, parameters }) } + TypeName::Error => Ty::Unknown, // FIXME handle TypeKindId::Trait/Type here TypeName::TypeKindId(_) => unimplemented!(), TypeName::Placeholder(idx) => { @@ -323,9 +322,9 @@ where } impl ToChalk for Arc { - type Chalk = Arc>; + type Chalk = chalk_ir::Environment; - fn to_chalk(self, db: &impl HirDatabase) -> Arc> { + fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment { let mut clauses = Vec::new(); for pred in &self.predicates { if pred.is_error() { @@ -340,7 +339,7 @@ impl ToChalk for Arc { fn from_chalk( _db: &impl HirDatabase, - _env: Arc>, + _env: chalk_ir::Environment, ) -> Arc { unimplemented!() } From dba767802d05c493b7798b0173a2d102dcc73a95 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:01:55 +0300 Subject: [PATCH 059/102] make file id repr private again --- crates/ra_hir_expand/src/expand.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/crates/ra_hir_expand/src/expand.rs b/crates/ra_hir_expand/src/expand.rs index 6517ea84da70..3921175cb0de 100644 --- a/crates/ra_hir_expand/src/expand.rs +++ b/crates/ra_hir_expand/src/expand.rs @@ -39,20 +39,23 @@ macro_rules! impl_intern_key { /// finite (because everything bottoms out at the real `FileId`) and small /// (`MacroCallId` uses the location interner). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum HirFileId { +pub struct HirFileId(HirFileIdRepr); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum HirFileIdRepr { FileId(FileId), MacroFile(MacroFile), } impl From for HirFileId { fn from(id: FileId) -> Self { - HirFileId::FileId(id) + HirFileId(HirFileIdRepr::FileId(id)) } } impl From for HirFileId { fn from(id: MacroFile) -> Self { - HirFileId::MacroFile(id) + HirFileId(HirFileIdRepr::MacroFile(id)) } } @@ -60,9 +63,9 @@ impl HirFileId { /// For macro-expansion files, returns the file original source file the /// expansion originated from. pub fn original_file(self, db: &impl AstDatabase) -> FileId { - match self { - HirFileId::FileId(file_id) => file_id, - HirFileId::MacroFile(macro_file) => { + match self.0 { + HirFileIdRepr::FileId(file_id) => file_id, + HirFileIdRepr::MacroFile(macro_file) => { let loc = db.lookup_intern_macro(macro_file.macro_call_id); loc.ast_id.file_id().original_file(db) } @@ -71,9 +74,9 @@ impl HirFileId { /// Get the crate which the macro lives in, if it is a macro file. pub fn macro_crate(self, db: &impl AstDatabase) -> Option { - match self { - HirFileId::FileId(_) => None, - HirFileId::MacroFile(macro_file) => { + match self.0 { + HirFileIdRepr::FileId(_) => None, + HirFileIdRepr::MacroFile(macro_file) => { let loc = db.lookup_intern_macro(macro_file.macro_call_id); Some(loc.def.krate) } @@ -215,9 +218,11 @@ pub(crate) fn parse_or_expand_query( db: &impl AstDatabase, file_id: HirFileId, ) -> Option { - match file_id { - HirFileId::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), - HirFileId::MacroFile(macro_file) => db.parse_macro(macro_file).map(|it| it.syntax_node()), + match file_id.0 { + HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), + HirFileIdRepr::MacroFile(macro_file) => { + db.parse_macro(macro_file).map(|it| it.syntax_node()) + } } } From 6bf7faf315c57dbec6cb3d5a7c7089016603b309 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:11:42 +0300 Subject: [PATCH 060/102] flatten hir_expand --- crates/ra_hir/src/ids.rs | 4 +- crates/ra_hir/src/source_id.rs | 2 +- crates/ra_hir_expand/src/db.rs | 80 +++++++++- crates/ra_hir_expand/src/expand.rs | 248 ----------------------------- crates/ra_hir_expand/src/lib.rs | 170 +++++++++++++++++++- 5 files changed, 243 insertions(+), 261 deletions(-) delete mode 100644 crates/ra_hir_expand/src/expand.rs diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index eb2d2340991a..dea288eb7bc9 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -15,9 +15,7 @@ use crate::{ AstId, FileAstId, Module, Source, }; -pub use hir_expand::expand::{ - HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, -}; +pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind}; macro_rules! impl_intern_key { ($name:ident) => { diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index b37474418fd7..c69a2afeb683 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -2,5 +2,5 @@ pub use hir_expand::{ ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}, - expand::AstId, + AstId, }; diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 7133b61dba5d..912599e57166 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -1,11 +1,13 @@ use std::sync::Arc; +use mbe::MacroRules; use ra_db::{salsa, SourceDatabase}; -use ra_syntax::{Parse, SyntaxNode}; +use ra_prof::profile; +use ra_syntax::{AstNode, Parse, SyntaxNode}; use crate::{ ast_id_map::{AstIdMap, ErasedFileAstId}, - expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, + HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, }; #[salsa::query_group(AstDatabaseStorage)] @@ -15,18 +17,13 @@ pub trait AstDatabase: SourceDatabase { fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode; #[salsa::transparent] - #[salsa::invoke(crate::expand::parse_or_expand_query)] fn parse_or_expand(&self, file_id: HirFileId) -> Option; #[salsa::interned] fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; - #[salsa::invoke(crate::expand::macro_arg_query)] fn macro_arg(&self, id: MacroCallId) -> Option>; - #[salsa::invoke(crate::expand::macro_def_query)] fn macro_def(&self, id: MacroDefId) -> Option>; - #[salsa::invoke(crate::expand::parse_macro_query)] fn parse_macro(&self, macro_file: MacroFile) -> Option>; - #[salsa::invoke(crate::expand::macro_expand_query)] fn macro_expand(&self, macro_call: MacroCallId) -> Result, String>; } @@ -44,3 +41,72 @@ pub(crate) fn ast_id_to_node( let node = db.parse_or_expand(file_id).unwrap(); db.ast_id_map(file_id)[ast_id].to_node(&node) } + +pub(crate) fn macro_def(db: &impl AstDatabase, id: MacroDefId) -> Option> { + let macro_call = id.ast_id.to_node(db); + let arg = macro_call.token_tree()?; + let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { + log::warn!("fail on macro_def to token tree: {:#?}", arg); + None + })?; + let rules = MacroRules::parse(&tt).ok().or_else(|| { + log::warn!("fail on macro_def parse: {:#?}", tt); + None + })?; + Some(Arc::new(rules)) +} + +pub(crate) fn macro_arg(db: &impl AstDatabase, id: MacroCallId) -> Option> { + let loc = db.lookup_intern_macro(id); + let macro_call = loc.ast_id.to_node(db); + let arg = macro_call.token_tree()?; + let (tt, _) = mbe::ast_to_token_tree(&arg)?; + Some(Arc::new(tt)) +} + +pub(crate) fn macro_expand( + db: &impl AstDatabase, + id: MacroCallId, +) -> Result, String> { + let loc = db.lookup_intern_macro(id); + let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; + + let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; + let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; + // Set a hard limit for the expanded tt + let count = tt.count(); + if count > 65536 { + return Err(format!("Total tokens count exceed limit : count = {}", count)); + } + Ok(Arc::new(tt)) +} + +pub(crate) fn parse_or_expand(db: &impl AstDatabase, file_id: HirFileId) -> Option { + match file_id.0 { + HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), + HirFileIdRepr::MacroFile(macro_file) => { + db.parse_macro(macro_file).map(|it| it.syntax_node()) + } + } +} + +pub(crate) fn parse_macro( + db: &impl AstDatabase, + macro_file: MacroFile, +) -> Option> { + let _p = profile("parse_macro_query"); + let macro_call_id = macro_file.macro_call_id; + let tt = db + .macro_expand(macro_call_id) + .map_err(|err| { + // Note: + // The final goal we would like to make all parse_macro success, + // such that the following log will not call anyway. + log::warn!("fail on macro_parse: (reason: {})", err,); + }) + .ok()?; + match macro_file.macro_file_kind { + MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), + MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), + } +} diff --git a/crates/ra_hir_expand/src/expand.rs b/crates/ra_hir_expand/src/expand.rs deleted file mode 100644 index 3921175cb0de..000000000000 --- a/crates/ra_hir_expand/src/expand.rs +++ /dev/null @@ -1,248 +0,0 @@ -use std::{ - hash::{Hash, Hasher}, - sync::Arc, -}; - -use mbe::MacroRules; -use ra_db::{salsa, CrateId, FileId}; -use ra_prof::profile; -use ra_syntax::{ - ast::{self, AstNode}, - Parse, SyntaxNode, -}; - -use crate::{ast_id_map::FileAstId, db::AstDatabase}; - -macro_rules! impl_intern_key { - ($name:ident) => { - impl salsa::InternKey for $name { - fn from_intern_id(v: salsa::InternId) -> Self { - $name(v) - } - fn as_intern_id(&self) -> salsa::InternId { - self.0 - } - } - }; -} - -/// Input to the analyzer is a set of files, where each file is identified by -/// `FileId` and contains source code. However, another source of source code in -/// Rust are macros: each macro can be thought of as producing a "temporary -/// file". To assign an id to such a file, we use the id of the macro call that -/// produced the file. So, a `HirFileId` is either a `FileId` (source code -/// written by user), or a `MacroCallId` (source code produced by macro). -/// -/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file -/// containing the call plus the offset of the macro call in the file. Note that -/// this is a recursive definition! However, the size_of of `HirFileId` is -/// finite (because everything bottoms out at the real `FileId`) and small -/// (`MacroCallId` uses the location interner). -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HirFileId(HirFileIdRepr); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum HirFileIdRepr { - FileId(FileId), - MacroFile(MacroFile), -} - -impl From for HirFileId { - fn from(id: FileId) -> Self { - HirFileId(HirFileIdRepr::FileId(id)) - } -} - -impl From for HirFileId { - fn from(id: MacroFile) -> Self { - HirFileId(HirFileIdRepr::MacroFile(id)) - } -} - -impl HirFileId { - /// For macro-expansion files, returns the file original source file the - /// expansion originated from. - pub fn original_file(self, db: &impl AstDatabase) -> FileId { - match self.0 { - HirFileIdRepr::FileId(file_id) => file_id, - HirFileIdRepr::MacroFile(macro_file) => { - let loc = db.lookup_intern_macro(macro_file.macro_call_id); - loc.ast_id.file_id().original_file(db) - } - } - } - - /// Get the crate which the macro lives in, if it is a macro file. - pub fn macro_crate(self, db: &impl AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc = db.lookup_intern_macro(macro_file.macro_call_id); - Some(loc.def.krate) - } - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroFile { - macro_call_id: MacroCallId, - macro_file_kind: MacroFileKind, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroFileKind { - Items, - Expr, -} - -/// `MacroCallId` identifies a particular macro invocation, like -/// `println!("Hello, {}", world)`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroCallId(salsa::InternId); -impl_intern_key!(MacroCallId); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroDefId { - pub krate: CrateId, - pub ast_id: AstId, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MacroCallLoc { - pub def: MacroDefId, - pub ast_id: AstId, -} - -impl MacroCallId { - pub fn loc(self, db: &impl AstDatabase) -> MacroCallLoc { - db.lookup_intern_macro(self) - } - - pub fn as_file(self, kind: MacroFileKind) -> HirFileId { - let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; - macro_file.into() - } -} - -impl MacroCallLoc { - pub fn id(self, db: &impl AstDatabase) -> MacroCallId { - db.intern_macro(self) - } -} - -/// `AstId` points to an AST node in any file. -/// -/// It is stable across reparses, and can be used as salsa key/value. -// FIXME: isn't this just a `Source>` ? -#[derive(Debug)] -pub struct AstId { - file_id: HirFileId, - file_ast_id: FileAstId, -} - -impl Clone for AstId { - fn clone(&self) -> AstId { - *self - } -} -impl Copy for AstId {} - -impl PartialEq for AstId { - fn eq(&self, other: &Self) -> bool { - (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id) - } -} -impl Eq for AstId {} -impl Hash for AstId { - fn hash(&self, hasher: &mut H) { - (self.file_id, self.file_ast_id).hash(hasher); - } -} - -impl AstId { - pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { - AstId { file_id, file_ast_id } - } - - pub fn file_id(&self) -> HirFileId { - self.file_id - } - - pub fn to_node(&self, db: &impl AstDatabase) -> N { - let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); - N::cast(syntax_node).unwrap() - } -} - -pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option> { - let macro_call = id.ast_id.to_node(db); - let arg = macro_call.token_tree()?; - let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { - log::warn!("fail on macro_def to token tree: {:#?}", arg); - None - })?; - let rules = MacroRules::parse(&tt).ok().or_else(|| { - log::warn!("fail on macro_def parse: {:#?}", tt); - None - })?; - Some(Arc::new(rules)) -} - -pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option> { - let loc = db.lookup_intern_macro(id); - let macro_call = loc.ast_id.to_node(db); - let arg = macro_call.token_tree()?; - let (tt, _) = mbe::ast_to_token_tree(&arg)?; - Some(Arc::new(tt)) -} - -pub(crate) fn macro_expand_query( - db: &impl AstDatabase, - id: MacroCallId, -) -> Result, String> { - let loc = db.lookup_intern_macro(id); - let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; - - let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; - let tt = macro_rules.expand(¯o_arg).map_err(|err| format!("{:?}", err))?; - // Set a hard limit for the expanded tt - let count = tt.count(); - if count > 65536 { - return Err(format!("Total tokens count exceed limit : count = {}", count)); - } - Ok(Arc::new(tt)) -} - -pub(crate) fn parse_or_expand_query( - db: &impl AstDatabase, - file_id: HirFileId, -) -> Option { - match file_id.0 { - HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), - HirFileIdRepr::MacroFile(macro_file) => { - db.parse_macro(macro_file).map(|it| it.syntax_node()) - } - } -} - -pub(crate) fn parse_macro_query( - db: &impl AstDatabase, - macro_file: MacroFile, -) -> Option> { - let _p = profile("parse_macro_query"); - let macro_call_id = macro_file.macro_call_id; - let tt = db - .macro_expand(macro_call_id) - .map_err(|err| { - // Note: - // The final goal we would like to make all parse_macro success, - // such that the following log will not call anyway. - log::warn!("fail on macro_parse: (reason: {})", err,); - }) - .ok()?; - match macro_file.macro_file_kind { - MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), - MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), - } -} diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 6ccb11068127..002a5b45a4b2 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -5,7 +5,173 @@ //! `ra_hir_def`, so this crates doesn't contain a lot at the moment. pub mod db; - pub mod ast_id_map; -pub mod expand; +use std::hash::{Hash, Hasher}; + +use ra_db::{salsa, CrateId, FileId}; +use ra_syntax::ast::{self, AstNode}; + +use crate::{ast_id_map::FileAstId, db::AstDatabase}; + +macro_rules! impl_intern_key { + ($name:ident) => { + impl salsa::InternKey for $name { + fn from_intern_id(v: salsa::InternId) -> Self { + $name(v) + } + fn as_intern_id(&self) -> salsa::InternId { + self.0 + } + } + }; +} + +/// Input to the analyzer is a set of files, where each file is identified by +/// `FileId` and contains source code. However, another source of source code in +/// Rust are macros: each macro can be thought of as producing a "temporary +/// file". To assign an id to such a file, we use the id of the macro call that +/// produced the file. So, a `HirFileId` is either a `FileId` (source code +/// written by user), or a `MacroCallId` (source code produced by macro). +/// +/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file +/// containing the call plus the offset of the macro call in the file. Note that +/// this is a recursive definition! However, the size_of of `HirFileId` is +/// finite (because everything bottoms out at the real `FileId`) and small +/// (`MacroCallId` uses the location interner). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct HirFileId(HirFileIdRepr); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum HirFileIdRepr { + FileId(FileId), + MacroFile(MacroFile), +} + +impl From for HirFileId { + fn from(id: FileId) -> Self { + HirFileId(HirFileIdRepr::FileId(id)) + } +} + +impl From for HirFileId { + fn from(id: MacroFile) -> Self { + HirFileId(HirFileIdRepr::MacroFile(id)) + } +} + +impl HirFileId { + /// For macro-expansion files, returns the file original source file the + /// expansion originated from. + pub fn original_file(self, db: &impl AstDatabase) -> FileId { + match self.0 { + HirFileIdRepr::FileId(file_id) => file_id, + HirFileIdRepr::MacroFile(macro_file) => { + let loc = db.lookup_intern_macro(macro_file.macro_call_id); + loc.ast_id.file_id().original_file(db) + } + } + } + + /// Get the crate which the macro lives in, if it is a macro file. + pub fn macro_crate(self, db: &impl AstDatabase) -> Option { + match self.0 { + HirFileIdRepr::FileId(_) => None, + HirFileIdRepr::MacroFile(macro_file) => { + let loc = db.lookup_intern_macro(macro_file.macro_call_id); + Some(loc.def.krate) + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroFile { + macro_call_id: MacroCallId, + macro_file_kind: MacroFileKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MacroFileKind { + Items, + Expr, +} + +/// `MacroCallId` identifies a particular macro invocation, like +/// `println!("Hello, {}", world)`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroCallId(salsa::InternId); +impl_intern_key!(MacroCallId); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MacroDefId { + pub krate: CrateId, + pub ast_id: AstId, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroCallLoc { + pub def: MacroDefId, + pub ast_id: AstId, +} + +impl MacroCallId { + pub fn loc(self, db: &impl AstDatabase) -> MacroCallLoc { + db.lookup_intern_macro(self) + } + + pub fn as_file(self, kind: MacroFileKind) -> HirFileId { + let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; + macro_file.into() + } +} + +impl MacroCallLoc { + pub fn id(self, db: &impl AstDatabase) -> MacroCallId { + db.intern_macro(self) + } +} + +/// `AstId` points to an AST node in any file. +/// +/// It is stable across reparses, and can be used as salsa key/value. +// FIXME: isn't this just a `Source>` ? +#[derive(Debug)] +pub struct AstId { + file_id: HirFileId, + file_ast_id: FileAstId, +} + +impl Clone for AstId { + fn clone(&self) -> AstId { + *self + } +} +impl Copy for AstId {} + +impl PartialEq for AstId { + fn eq(&self, other: &Self) -> bool { + (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id) + } +} +impl Eq for AstId {} +impl Hash for AstId { + fn hash(&self, hasher: &mut H) { + (self.file_id, self.file_ast_id).hash(hasher); + } +} + +impl AstId { + pub fn new(file_id: HirFileId, file_ast_id: FileAstId) -> AstId { + AstId { file_id, file_ast_id } + } + + pub fn file_id(&self) -> HirFileId { + self.file_id + } + + pub fn to_node(&self, db: &impl AstDatabase) -> N { + let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); + N::cast(syntax_node).unwrap() + } +} From 858dd48af26e851897b2e8d2fbf757f3adfbc92c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:20:08 +0300 Subject: [PATCH 061/102] less generics --- crates/ra_hir_expand/src/ast_id_map.rs | 14 ++++++++------ crates/ra_hir_expand/src/db.rs | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index c3b389102ac5..2f43abe152f1 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs @@ -75,17 +75,19 @@ impl AstIdMap { } pub fn ast_id(&self, item: &N) -> FileAstId { - let ptr = SyntaxNodePtr::new(item.syntax()); - let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) { + let raw = self.erased_ast_id(item.syntax()); + FileAstId { raw, _ty: PhantomData } + } + fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { + let ptr = SyntaxNodePtr::new(item); + match self.arena.iter().find(|(_id, i)| **i == ptr) { Some((it, _)) => it, None => panic!( "Can't find {:?} in AstIdMap:\n{:?}", - item.syntax(), + item, self.arena.iter().map(|(_id, i)| i).collect::>(), ), - }; - - FileAstId { raw, _ty: PhantomData } + } } fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 912599e57166..12aa7ad0ef48 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -10,6 +10,7 @@ use crate::{ HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, }; +// FIXME: rename to ExpandDatabase #[salsa::query_group(AstDatabaseStorage)] pub trait AstDatabase: SourceDatabase { fn ast_id_map(&self, file_id: HirFileId) -> Arc; From d095d9273eb2c03d1c28e0122c21fccf4099660e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:22:20 +0300 Subject: [PATCH 062/102] remove unused query --- crates/ra_hir_expand/src/db.rs | 15 ++------------- crates/ra_hir_expand/src/lib.rs | 5 +++-- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 12aa7ad0ef48..8b92d4c1f8cc 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -6,16 +6,14 @@ use ra_prof::profile; use ra_syntax::{AstNode, Parse, SyntaxNode}; use crate::{ - ast_id_map::{AstIdMap, ErasedFileAstId}, - HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind, + ast_id_map::AstIdMap, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, + MacroFile, MacroFileKind, }; // FIXME: rename to ExpandDatabase #[salsa::query_group(AstDatabaseStorage)] pub trait AstDatabase: SourceDatabase { fn ast_id_map(&self, file_id: HirFileId) -> Arc; - #[salsa::transparent] - fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode; #[salsa::transparent] fn parse_or_expand(&self, file_id: HirFileId) -> Option; @@ -34,15 +32,6 @@ pub(crate) fn ast_id_map(db: &impl AstDatabase, file_id: HirFileId) -> Arc SyntaxNode { - let node = db.parse_or_expand(file_id).unwrap(); - db.ast_id_map(file_id)[ast_id].to_node(&node) -} - pub(crate) fn macro_def(db: &impl AstDatabase, id: MacroDefId) -> Option> { let macro_call = id.ast_id.to_node(db); let arg = macro_call.token_tree()?; diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 002a5b45a4b2..1fb12437414a 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -171,7 +171,8 @@ impl AstId { } pub fn to_node(&self, db: &impl AstDatabase) -> N { - let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.into()); - N::cast(syntax_node).unwrap() + let root = db.parse_or_expand(self.file_id).unwrap(); + let node = db.ast_id_map(self.file_id)[self.file_ast_id.into()].to_node(&root); + N::cast(node).unwrap() } } From 2a5254c106df41dc53c34508e9f5ba77243b7a51 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:25:46 +0300 Subject: [PATCH 063/102] reduce visibility --- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/source_id.rs | 2 +- crates/ra_hir_expand/src/ast_id_map.rs | 22 ++++++---------------- crates/ra_hir_expand/src/lib.rs | 3 +-- 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index ca261e8f541a..227e931833fc 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -80,7 +80,7 @@ pub use self::{ path::{Path, PathKind}, resolve::ScopeDef, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, - source_id::{AstIdMap, ErasedFileAstId}, + source_id::AstIdMap, ty::{ display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index c69a2afeb683..463b1d45352e 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here pub use hir_expand::{ - ast_id_map::{AstIdMap, ErasedFileAstId, FileAstId}, + ast_id_map::{AstIdMap, FileAstId}, AstId, }; diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index 2f43abe152f1..919ede0a03d5 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs @@ -8,11 +8,10 @@ use std::{ hash::{Hash, Hasher}, marker::PhantomData, - ops, }; use ra_arena::{impl_arena_id, Arena, RawId}; -use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr}; +use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. #[derive(Debug)] @@ -40,14 +39,8 @@ impl Hash for FileAstId { } } -impl From> for ErasedFileAstId { - fn from(id: FileAstId) -> Self { - id.raw - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ErasedFileAstId(RawId); +struct ErasedFileAstId(RawId); impl_arena_id!(ErasedFileAstId); /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. @@ -90,18 +83,15 @@ impl AstIdMap { } } + pub fn get(&self, id: FileAstId) -> AstPtr { + self.arena[id.raw].cast::().unwrap() + } + fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { self.arena.alloc(SyntaxNodePtr::new(item)) } } -impl ops::Index for AstIdMap { - type Output = SyntaxNodePtr; - fn index(&self, index: ErasedFileAstId) -> &SyntaxNodePtr { - &self.arena[index] - } -} - /// Walks the subtree in bfs order, calling `f` for each node. fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) { let mut curr_layer = vec![node.clone()]; diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 1fb12437414a..a31b9fa4cdd2 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -172,7 +172,6 @@ impl AstId { pub fn to_node(&self, db: &impl AstDatabase) -> N { let root = db.parse_or_expand(self.file_id).unwrap(); - let node = db.ast_id_map(self.file_id)[self.file_ast_id.into()].to_node(&root); - N::cast(node).unwrap() + db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) } } From b8b7969bfb261fa86b4c38024f873444145fe7a2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 15:53:25 +0300 Subject: [PATCH 064/102] remove empty module --- crates/ra_hir/src/lib.rs | 15 ++++++--------- crates/ra_hir/src/source_id.rs | 6 ------ 2 files changed, 6 insertions(+), 15 deletions(-) delete mode 100644 crates/ra_hir/src/source_id.rs diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 227e931833fc..5762b9e52f6b 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -35,7 +35,6 @@ pub mod mock; mod path; pub mod source_binder; -mod source_id; mod ids; mod name; mod nameres; @@ -60,14 +59,13 @@ pub mod from_source; #[cfg(test)] mod marks; -use crate::{ - ids::MacroFileKind, - name::AsName, - resolve::Resolver, - source_id::{AstId, FileAstId}, -}; +use hir_expand::{ast_id_map::FileAstId, AstId}; -pub use self::{ +use crate::{ids::MacroFileKind, name::AsName, resolve::Resolver}; + +use hir_expand::ast_id_map::AstIdMap; + +pub use crate::{ adt::VariantDef, either::Either, expr::ExprScopes, @@ -80,7 +78,6 @@ pub use self::{ path::{Path, PathKind}, resolve::ScopeDef, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, - source_id::AstIdMap, ty::{ display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs deleted file mode 100644 index 463b1d45352e..000000000000 --- a/crates/ra_hir/src/source_id.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! FIXME: write short doc here - -pub use hir_expand::{ - ast_id_map::{AstIdMap, FileAstId}, - AstId, -}; From 7de6eaa58ae994a5c5d39a66253e347fb039fa94 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 16:01:14 +0300 Subject: [PATCH 065/102] remove not that useful indirection --- crates/ra_hir/src/expr/lower.rs | 2 +- crates/ra_hir/src/impl_block.rs | 2 +- crates/ra_hir/src/nameres/collector.rs | 4 ++-- crates/ra_hir_expand/src/lib.rs | 18 ++++-------------- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 24733b3de382..b3a9a2e6b9a6 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -465,7 +465,7 @@ where if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { - let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); + let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id }); let file_id = call_id.as_file(MacroFileKind::Expr); if let Some(node) = self.db.parse_or_expand(file_id) { if let Some(expr) = ast::Expr::cast(node) { diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 9c739f3f166c..1a52236806d6 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -263,7 +263,7 @@ impl ModuleImplBlocks { { if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) { - let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); + let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id }); let file_id = call_id.as_file(MacroFileKind::Items); if let Some(item_list) = db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 885ea57a1c56..dc591e8d349a 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -448,7 +448,7 @@ where ); if let Some(def) = resolved_res.resolved_def.get_macros() { - let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); + let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id }); resolved.push((*module_id, call_id, def.id)); res = ReachedFixedPoint::No; return false; @@ -690,7 +690,7 @@ where self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) }) { let def = macro_def.id; - let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); + let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id }); self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); return; diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index a31b9fa4cdd2..9100bd15cc73 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -1,8 +1,8 @@ -//! `ra_hir_def` contains initial "phases" of the compiler. Roughly, everything -//! before types. +//! `ra_hir_expand` deals with macro expansion. //! -//! Note that we are in the process of moving parts of `ra_hir` into -//! `ra_hir_def`, so this crates doesn't contain a lot at the moment. +//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax +//! tree originates not from the text of some `FileId`, but from some macro +//! expansion. pub mod db; pub mod ast_id_map; @@ -116,22 +116,12 @@ pub struct MacroCallLoc { } impl MacroCallId { - pub fn loc(self, db: &impl AstDatabase) -> MacroCallLoc { - db.lookup_intern_macro(self) - } - pub fn as_file(self, kind: MacroFileKind) -> HirFileId { let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; macro_file.into() } } -impl MacroCallLoc { - pub fn id(self, db: &impl AstDatabase) -> MacroCallId { - db.intern_macro(self) - } -} - /// `AstId` points to an AST node in any file. /// /// It is stable across reparses, and can be used as salsa key/value. From 1ec418c3b8af987e1531c5cfd5bc1e817f237036 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 16:03:29 +0300 Subject: [PATCH 066/102] add doc comment --- crates/ra_hir_expand/src/db.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 8b92d4c1f8cc..dc4944c05198 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -1,3 +1,5 @@ +//! Defines database & queries for macro expansion. + use std::sync::Arc; use mbe::MacroRules; From 3260639608112738089d134c47c1d575515c9cb7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 16:08:06 +0300 Subject: [PATCH 067/102] reduce visibility --- crates/ra_hir_expand/src/ast_id_map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index 919ede0a03d5..cb464c3ff17d 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs @@ -50,7 +50,7 @@ pub struct AstIdMap { } impl AstIdMap { - pub fn from_source(node: &SyntaxNode) -> AstIdMap { + pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { assert!(node.parent().is_none()); let mut res = AstIdMap { arena: Arena::default() }; // By walking the tree in bread-first order we make sure that parents @@ -83,7 +83,7 @@ impl AstIdMap { } } - pub fn get(&self, id: FileAstId) -> AstPtr { + pub(crate) fn get(&self, id: FileAstId) -> AstPtr { self.arena[id.raw].cast::().unwrap() } From 99b6ecfab061396613c5f459fae43ea17b5675b8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 16:12:54 +0300 Subject: [PATCH 068/102] switch expand to dyn Trait --- crates/ra_hir_expand/src/db.rs | 12 ++++++------ crates/ra_hir_expand/src/lib.rs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index dc4944c05198..a4ee9a529a1c 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -28,13 +28,13 @@ pub trait AstDatabase: SourceDatabase { fn macro_expand(&self, macro_call: MacroCallId) -> Result, String>; } -pub(crate) fn ast_id_map(db: &impl AstDatabase, file_id: HirFileId) -> Arc { +pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { let map = db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it)); Arc::new(map) } -pub(crate) fn macro_def(db: &impl AstDatabase, id: MacroDefId) -> Option> { +pub(crate) fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option> { let macro_call = id.ast_id.to_node(db); let arg = macro_call.token_tree()?; let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { @@ -48,7 +48,7 @@ pub(crate) fn macro_def(db: &impl AstDatabase, id: MacroDefId) -> Option Option> { +pub(crate) fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option> { let loc = db.lookup_intern_macro(id); let macro_call = loc.ast_id.to_node(db); let arg = macro_call.token_tree()?; @@ -57,7 +57,7 @@ pub(crate) fn macro_arg(db: &impl AstDatabase, id: MacroCallId) -> Option Result, String> { let loc = db.lookup_intern_macro(id); @@ -73,7 +73,7 @@ pub(crate) fn macro_expand( Ok(Arc::new(tt)) } -pub(crate) fn parse_or_expand(db: &impl AstDatabase, file_id: HirFileId) -> Option { +pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option { match file_id.0 { HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), HirFileIdRepr::MacroFile(macro_file) => { @@ -83,7 +83,7 @@ pub(crate) fn parse_or_expand(db: &impl AstDatabase, file_id: HirFileId) -> Opti } pub(crate) fn parse_macro( - db: &impl AstDatabase, + db: &dyn AstDatabase, macro_file: MacroFile, ) -> Option> { let _p = profile("parse_macro_query"); diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 9100bd15cc73..749227465f5b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -63,7 +63,7 @@ impl From for HirFileId { impl HirFileId { /// For macro-expansion files, returns the file original source file the /// expansion originated from. - pub fn original_file(self, db: &impl AstDatabase) -> FileId { + pub fn original_file(self, db: &dyn AstDatabase) -> FileId { match self.0 { HirFileIdRepr::FileId(file_id) => file_id, HirFileIdRepr::MacroFile(macro_file) => { @@ -74,7 +74,7 @@ impl HirFileId { } /// Get the crate which the macro lives in, if it is a macro file. - pub fn macro_crate(self, db: &impl AstDatabase) -> Option { + pub fn macro_crate(self, db: &dyn AstDatabase) -> Option { match self.0 { HirFileIdRepr::FileId(_) => None, HirFileIdRepr::MacroFile(macro_file) => { @@ -160,7 +160,7 @@ impl AstId { self.file_id } - pub fn to_node(&self, db: &impl AstDatabase) -> N { + pub fn to_node(&self, db: &dyn AstDatabase) -> N { let root = db.parse_or_expand(self.file_id).unwrap(); db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) } From bca708ba4c5eb474448ef2f2882a66ec935f2fee Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Oct 2019 16:19:08 +0300 Subject: [PATCH 069/102] cleanup --- crates/ra_hir/src/debug.rs | 6 ------ crates/ra_hir/src/lib.rs | 7 ++++--- crates/ra_hir_expand/src/lib.rs | 22 ++++++++-------------- crates/ra_ide_api/Cargo.toml | 5 ++++- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs index c3f890ed4a1a..4f3e922c3c5c 100644 --- a/crates/ra_hir/src/debug.rs +++ b/crates/ra_hir/src/debug.rs @@ -36,12 +36,6 @@ impl Module { } } -// impl HirFileId { -// pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ { -// debug_fn(move |fmt| db.debug_hir_file_id(self, fmt)) -// } -// } - pub trait HirDebugHelper: HirDatabase { fn crate_name(&self, _krate: CrateId) -> Option { None diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5762b9e52f6b..0f2d233bb1b9 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -59,12 +59,13 @@ pub mod from_source; #[cfg(test)] mod marks; -use hir_expand::{ast_id_map::FileAstId, AstId}; +use hir_expand::{ + ast_id_map::{AstIdMap, FileAstId}, + AstId, +}; use crate::{ids::MacroFileKind, name::AsName, resolve::Resolver}; -use hir_expand::ast_id_map::AstIdMap; - pub use crate::{ adt::VariantDef, either::Either, diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 749227465f5b..6b35386730c9 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -14,19 +14,6 @@ use ra_syntax::ast::{self, AstNode}; use crate::{ast_id_map::FileAstId, db::AstDatabase}; -macro_rules! impl_intern_key { - ($name:ident) => { - impl salsa::InternKey for $name { - fn from_intern_id(v: salsa::InternId) -> Self { - $name(v) - } - fn as_intern_id(&self) -> salsa::InternId { - self.0 - } - } - }; -} - /// Input to the analyzer is a set of files, where each file is identified by /// `FileId` and contains source code. However, another source of source code in /// Rust are macros: each macro can be thought of as producing a "temporary @@ -101,7 +88,14 @@ pub enum MacroFileKind { /// `println!("Hello, {}", world)`. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroCallId(salsa::InternId); -impl_intern_key!(MacroCallId); +impl salsa::InternKey for MacroCallId { + fn from_intern_id(v: salsa::InternId) -> Self { + MacroCallId(v) + } + fn as_intern_id(&self) -> salsa::InternId { + self.0 + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml index f66f0a6bade5..bf6ef12f3ffb 100644 --- a/crates/ra_ide_api/Cargo.toml +++ b/crates/ra_ide_api/Cargo.toml @@ -27,10 +27,13 @@ ra_db = { path = "../ra_db" } ra_cfg = { path = "../ra_cfg" } ra_fmt = { path = "../ra_fmt" } ra_prof = { path = "../ra_prof" } -hir = { path = "../ra_hir", package = "ra_hir" } test_utils = { path = "../test_utils" } ra_assists = { path = "../ra_assists" } +# ra_ide_api should depend only on the top-level `hir` package. if you need +# something from some `hir_xxx` subpackage, reexport the API via `hir`. +hir = { path = "../ra_hir", package = "ra_hir" } + [dev-dependencies] insta = "0.12.0" From b915bf2d05e3edf7e23e595b2b95bdcdaa0907fd Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 09:46:55 -0400 Subject: [PATCH 070/102] SigKind -> CallableKind --- .../src/display/function_signature.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 736b5d3dbeda..e21f8378d868 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -13,16 +13,16 @@ use crate::{ }; #[derive(Debug)] -pub enum SigKind { +pub enum CallableKind { Function, - Struct, - EnumVariant, + StructConstructor, + VariantConstructor, } /// Contains information about a function signature #[derive(Debug)] pub struct FunctionSignature { - pub kind: SigKind, + pub kind: CallableKind, /// Optional visibility pub visibility: Option, /// Name of the function @@ -69,7 +69,7 @@ impl FunctionSignature { Some( FunctionSignature { - kind: SigKind::Struct, + kind: CallableKind::StructConstructor, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), @@ -111,7 +111,7 @@ impl FunctionSignature { Some( FunctionSignature { - kind: SigKind::EnumVariant, + kind: CallableKind::VariantConstructor, visibility: None, name: Some(name), ret_type: None, @@ -140,7 +140,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { } FunctionSignature { - kind: SigKind::Function, + kind: CallableKind::Function, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node @@ -164,9 +164,9 @@ impl Display for FunctionSignature { if let Some(name) = &self.name { match self.kind { - SigKind::Function => write!(f, "fn {}", name)?, - SigKind::Struct => write!(f, "struct {}", name)?, - SigKind::EnumVariant => write!(f, "{}", name)?, + CallableKind::Function => write!(f, "fn {}", name)?, + CallableKind::StructConstructor => write!(f, "struct {}", name)?, + CallableKind::VariantConstructor => write!(f, "{}", name)?, } } From eb220a081b5e5867a1c063b42c02ec35535a19e5 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 12:16:55 -0400 Subject: [PATCH 071/102] Primitive signature help for mbe --- crates/ra_ide_api/src/call_info.rs | 36 +++++++++++++++++++ .../src/display/function_signature.rs | 22 ++++++++++++ 2 files changed, 58 insertions(+) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index d947ac50c2fc..729f4c2fff4e 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -36,6 +36,10 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { + let macro_def = analyzer.resolve_macro_call(db, &expr)?; + (CallInfo::with_macro(db, macro_def)?, false) + } }; // If we have a calling expression let's find which argument we are on @@ -77,9 +81,11 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0) } + + FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(), } } @@ -112,6 +122,7 @@ impl FnCallNode { match self { FnCallNode::CallExpr(expr) => expr.arg_list(), FnCallNode::MethodCallExpr(expr) => expr.arg_list(), + FnCallNode::MacroCallExpr(_) => None, } } } @@ -135,6 +146,12 @@ impl CallInfo { Some(CallInfo { signature, active_parameter: None }) } + fn with_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option { + let signature = FunctionSignature::from_macro(db, macro_def)?; + + Some(CallInfo { signature, active_parameter: None }) + } + fn parameters(&self) -> &[String] { &self.signature.parameters } @@ -549,4 +566,23 @@ fn main() { "#, ); } + + #[test] + fn fn_signature_for_macro() { + let info = call_info( + r#" +/// empty macro +macro_rules! foo { + () => {} +} + +fn f() { + foo!(<|>); +} + "#, + ); + + assert_eq!(info.label(), "foo!()"); + assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index e21f8378d868..9075ca443c3f 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -17,6 +17,7 @@ pub enum CallableKind { Function, StructConstructor, VariantConstructor, + Macro, } /// Contains information about a function signature @@ -123,6 +124,26 @@ impl FunctionSignature { .with_doc_opt(variant.docs(db)), ) } + + pub(crate) fn from_macro(db: &db::RootDatabase, macro_def: hir::MacroDef) -> Option { + let node: ast::MacroCall = macro_def.source(db).ast; + + let params = vec![]; + + Some( + FunctionSignature { + kind: CallableKind::Macro, + visibility: None, + name: node.name().map(|n| n.text().to_string()), + ret_type: None, + parameters: params, + generic_parameters: vec![], + where_predicates: vec![], + doc: None, + } + .with_doc_opt(macro_def.docs(db)), + ) + } } impl From<&'_ ast::FnDef> for FunctionSignature { @@ -167,6 +188,7 @@ impl Display for FunctionSignature { CallableKind::Function => write!(f, "fn {}", name)?, CallableKind::StructConstructor => write!(f, "struct {}", name)?, CallableKind::VariantConstructor => write!(f, "{}", name)?, + CallableKind::Macro => write!(f, "{}!", name)?, } } From 47cfdb4aa3f32a2288edbbc49aa107f4436593a7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 29 Oct 2019 18:14:15 +0100 Subject: [PATCH 072/102] Don't add a space after the opening brace in autoimport --- crates/ra_assists/src/assists/add_import.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index c8b9809f4c85..363ade016b04 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs @@ -545,7 +545,7 @@ fn make_assist_add_nested_import( if add_colon_colon { buf.push_str("::"); } - buf.push_str("{ "); + buf.push_str("{"); if add_self { buf.push_str("self, "); } @@ -734,7 +734,7 @@ impl std::io<|> for Foo { } ", " -use std::{ io, fmt}; +use std::{io, fmt}; impl io<|> for Foo { } @@ -753,7 +753,7 @@ impl std::fmt::Debug<|> for Foo { } ", " -use std::fmt::{ self, Debug, }; +use std::fmt::{self, Debug, }; impl Debug<|> for Foo { } @@ -772,7 +772,7 @@ impl std::fmt<|> for Foo { } ", " -use std::fmt::{ self, Debug}; +use std::fmt::{self, Debug}; impl fmt<|> for Foo { } @@ -848,7 +848,7 @@ impl std::fmt::nested::Display<|> for Foo { } ", " -use std::fmt::{ nested::Display, Debug}; +use std::fmt::{nested::Display, Debug}; impl Display<|> for Foo { } @@ -867,7 +867,7 @@ impl std::fmt::Display<|> for Foo { } ", " -use std::fmt::{ Display, nested::Debug}; +use std::fmt::{Display, nested::Debug}; impl Display<|> for Foo { } From 4ca5d4c353dc83ce758b286c0d1c6a44fd51fd81 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 15:25:31 -0400 Subject: [PATCH 073/102] Add missing test for label --- crates/ra_ide_api/src/call_info.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 729f4c2fff4e..175af3fd9298 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -448,6 +448,7 @@ pub fn foo(mut r: WriteHandler<()>) { "#, ); + assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); assert_eq!(info.active_parameter, Some(1)); assert_eq!( From 3c140050ff469364db88b4f582533937a8a7fe61 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 16:08:36 -0400 Subject: [PATCH 074/102] Profile all request handlers --- .../ra_lsp_server/src/main_loop/handlers.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 16fb0726600a..20f9aee138fb 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -27,6 +27,7 @@ use crate::{ }; pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { + let _p = profile("handle_analyzer_status"); let mut buf = world.status(); writeln!(buf, "\n\nrequests:").unwrap(); let requests = world.latest_requests.read(); @@ -38,6 +39,7 @@ pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result { } pub fn handle_syntax_tree(world: WorldSnapshot, params: req::SyntaxTreeParams) -> Result { + let _p = profile("handle_syntax_tree"); let id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(id)?; let text_range = params.range.map(|p| p.conv_with(&line_index)); @@ -172,6 +174,7 @@ pub fn handle_document_symbol( world: WorldSnapshot, params: req::DocumentSymbolParams, ) -> Result> { + let _p = profile("handle_document_symbol"); let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id)?; @@ -210,6 +213,7 @@ pub fn handle_workspace_symbol( world: WorldSnapshot, params: req::WorkspaceSymbolParams, ) -> Result>> { + let _p = profile("handle_workspace_symbol"); let all_symbols = params.query.contains('#'); let libs = params.query.contains('*'); let query = { @@ -253,6 +257,7 @@ pub fn handle_goto_definition( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_goto_definition"); let position = params.try_conv_with(&world)?; let nav_info = match world.analysis().goto_definition(position)? { None => return Ok(None), @@ -266,6 +271,7 @@ pub fn handle_goto_implementation( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_goto_implementation"); let position = params.try_conv_with(&world)?; let nav_info = match world.analysis().goto_implementation(position)? { None => return Ok(None), @@ -279,6 +285,7 @@ pub fn handle_goto_type_definition( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_goto_type_definition"); let position = params.try_conv_with(&world)?; let nav_info = match world.analysis().goto_type_definition(position)? { None => return Ok(None), @@ -292,6 +299,7 @@ pub fn handle_parent_module( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_parent_module"); let position = params.try_conv_with(&world)?; world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world) } @@ -300,6 +308,7 @@ pub fn handle_runnables( world: WorldSnapshot, params: req::RunnablesParams, ) -> Result> { + let _p = profile("handle_runnables"); let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id)?; let offset = params.position.map(|it| it.conv_with(&line_index)); @@ -341,6 +350,7 @@ pub fn handle_decorations( world: WorldSnapshot, params: TextDocumentIdentifier, ) -> Result> { + let _p = profile("handle_decorations"); let file_id = params.try_conv_with(&world)?; highlight(&world, file_id) } @@ -389,6 +399,7 @@ pub fn handle_folding_range( world: WorldSnapshot, params: FoldingRangeParams, ) -> Result>> { + let _p = profile("handle_folding_range"); let file_id = params.text_document.try_conv_with(&world)?; let folds = world.analysis().folding_ranges(file_id)?; let text = world.analysis().file_text(file_id)?; @@ -406,6 +417,7 @@ pub fn handle_signature_help( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_signature_help"); let position = params.try_conv_with(&world)?; if let Some(call_info) = world.analysis().call_info(position)? { let active_parameter = call_info.active_parameter.map(|it| it as i64); @@ -425,6 +437,7 @@ pub fn handle_hover( world: WorldSnapshot, params: req::TextDocumentPositionParams, ) -> Result> { + let _p = profile("handle_hover"); let position = params.try_conv_with(&world)?; let info = match world.analysis().hover(position)? { None => return Ok(None), @@ -523,6 +536,7 @@ pub fn handle_formatting( world: WorldSnapshot, params: DocumentFormattingParams, ) -> Result>> { + let _p = profile("handle_formatting"); let file_id = params.text_document.try_conv_with(&world)?; let file = world.analysis().file_text(file_id)?; @@ -645,6 +659,7 @@ pub fn handle_code_lens( world: WorldSnapshot, params: req::CodeLensParams, ) -> Result>> { + let _p = profile("handle_code_lens"); let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id)?; @@ -705,6 +720,7 @@ enum CodeLensResolveData { } pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result { + let _p = profile("handle_code_lens_resolve"); let data = code_lens.data.unwrap(); let resolve = serde_json::from_value(data)?; match resolve { @@ -776,6 +792,7 @@ pub fn publish_diagnostics( world: &WorldSnapshot, file_id: FileId, ) -> Result { + let _p = profile("publish_diagnostics"); let uri = world.file_id_to_uri(file_id)?; let line_index = world.analysis().file_line_index(file_id)?; let diagnostics = world @@ -798,6 +815,7 @@ pub fn publish_decorations( world: &WorldSnapshot, file_id: FileId, ) -> Result { + let _p = profile("publish_decorations"); let uri = world.file_id_to_uri(file_id)?; Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) } @@ -847,6 +865,7 @@ pub fn handle_inlay_hints( world: WorldSnapshot, params: InlayHintsParams, ) -> Result> { + let _p = profile("handle_inlay_hints"); let file_id = params.text_document.try_conv_with(&world)?; let analysis = world.analysis(); let line_index = analysis.file_line_index(file_id)?; From f3086dcc9c4a31fbe0050f345867167630b918aa Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 18:09:49 -0400 Subject: [PATCH 075/102] bump smallvec and unicode-segmentation --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18d2fb9d56e1..c7ec98226610 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -455,7 +455,7 @@ name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -802,7 +802,7 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1091,7 +1091,7 @@ dependencies = [ "ra_syntax 0.1.0", "ra_tt 0.1.0", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", ] @@ -1456,7 +1456,7 @@ dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "salsa-macros 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1553,7 +1553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1673,12 +1673,12 @@ name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-segmentation" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1955,7 +1955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cefaa50e76a6f10b86f36e640eb1739eafbd4084865067778463913e43a77ff3" "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" @@ -1969,7 +1969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" +"checksum unicode-segmentation 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc5415c074426c7c65db13bd647c23d78c0fb2e10dca0b8fb0f40058a59bccdf" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" From d7a7da8261795e15aef77ad306ada00c853fb913 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 10:39:12 +0300 Subject: [PATCH 076/102] don't add macro braces in use items --- .../ra_ide_api/src/completion/presentation.rs | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index aed4ce6d44bc..f7e98e6df2de 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -164,27 +164,32 @@ impl Completions { name: Option, macro_: hir::MacroDef, ) { - let ast_node = macro_.source(ctx.db).ast; - if let Some(name) = name { - let detail = macro_label(&ast_node); + let name = match name { + Some(it) => it, + None => return, + }; - let docs = macro_.docs(ctx.db); + let ast_node = macro_.source(ctx.db).ast; + let detail = macro_label(&ast_node); + + let docs = macro_.docs(ctx.db); + let macro_declaration = format!("{}!", name); + + let mut builder = + CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) + .kind(CompletionItemKind::Macro) + .set_documentation(docs.clone()) + .detail(detail); + + builder = if ctx.use_item_syntax.is_some() { + builder.insert_text(name) + } else { let macro_braces_to_insert = self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); - let macro_declaration = name + "!"; + builder.insert_snippet(macro_declaration + macro_braces_to_insert) + }; - let builder = CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - ¯o_declaration, - ) - .kind(CompletionItemKind::Macro) - .set_documentation(docs) - .detail(detail) - .insert_snippet(macro_declaration + macro_braces_to_insert); - - self.add(builder); - } + self.add(builder); } fn add_function_with_name( @@ -281,10 +286,11 @@ fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> b #[cfg(test)] mod tests { - use crate::completion::{do_completion, CompletionItem, CompletionKind}; use insta::assert_debug_snapshot; use test_utils::covers; + use crate::completion::{do_completion, CompletionItem, CompletionKind}; + fn do_reference_completion(code: &str) -> Vec { do_completion(code, CompletionKind::Reference) } @@ -576,4 +582,34 @@ mod tests { "### ); } + + #[test] + fn dont_insert_macro_call_braces_in_use() { + assert_debug_snapshot!( + do_reference_completion( + r" + //- /main.rs + use foo::<|>; + + //- /foo/lib.rs + #[macro_export] + macro_rules frobnicate { + () => () + } + " + ), + @r###" + [ + CompletionItem { + label: "frobnicate!", + source_range: [9; 9), + delete: [9; 9), + insert: "frobnicate", + kind: Macro, + detail: "#[macro_export]\nmacro_rules! frobnicate", + }, + ] + "### + ) + } } From 56bc874f1d14922686b26afc8793b7e57a652990 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 09:29:55 +0300 Subject: [PATCH 077/102] move ty interning to ty --- crates/ra_hir/src/db.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 6d34c671dce3..da8ae6ef4741 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -49,12 +49,6 @@ pub trait InternDatabase: SourceDatabase { fn intern_trait(&self, loc: ids::ItemLoc) -> ids::TraitId; #[salsa::interned] fn intern_type_alias(&self, loc: ids::ItemLoc) -> ids::TypeAliasId; - - // Interned IDs for Chalk integration - #[salsa::interned] - fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; - #[salsa::interned] - fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; } // This database uses `AstDatabase` internally, @@ -176,6 +170,12 @@ pub trait HirDatabase: DefDatabase + AstDatabase { #[salsa::invoke(crate::ty::traits::trait_solver_query)] fn trait_solver(&self, krate: Crate) -> crate::ty::traits::TraitSolver; + // Interned IDs for Chalk integration + #[salsa::interned] + fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; + #[salsa::interned] + fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; + #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc; From a136cc0653d2b4133fb6387009cfdbaf3e2cf275 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 12:27:54 +0300 Subject: [PATCH 078/102] introduce ra_hir_def --- Cargo.lock | 12 ++++ crates/ra_hir/Cargo.toml | 1 + crates/ra_hir/src/code_model.rs | 77 ++++++++++++----------- crates/ra_hir/src/code_model/src.rs | 10 +-- crates/ra_hir/src/from_source.rs | 2 +- crates/ra_hir/src/impl_block.rs | 2 +- crates/ra_hir/src/lang_item.rs | 16 ++--- crates/ra_hir/src/nameres.rs | 36 +++++------ crates/ra_hir/src/nameres/collector.rs | 23 ++++--- crates/ra_hir/src/resolve.rs | 17 ++--- crates/ra_hir/src/ty/method_resolution.rs | 12 ++-- crates/ra_hir/src/ty/traits/chalk.rs | 4 +- crates/ra_hir_def/Cargo.toml | 13 ++++ crates/ra_hir_def/src/lib.rs | 14 +++++ 14 files changed, 139 insertions(+), 100 deletions(-) create mode 100644 crates/ra_hir_def/Cargo.toml create mode 100644 crates/ra_hir_def/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c7ec98226610..a7643362095b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1003,6 +1003,7 @@ dependencies = [ "ra_arena 0.1.0", "ra_cfg 0.1.0", "ra_db 0.1.0", + "ra_hir_def 0.1.0", "ra_hir_expand 0.1.0", "ra_mbe 0.1.0", "ra_prof 0.1.0", @@ -1013,6 +1014,17 @@ dependencies = [ "test_utils 0.1.0", ] +[[package]] +name = "ra_hir_def" +version = "0.1.0" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ra_arena 0.1.0", + "ra_db 0.1.0", + "ra_prof 0.1.0", + "ra_syntax 0.1.0", +] + [[package]] name = "ra_hir_expand" version = "0.1.0" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 143dae6bdcdb..5df371bc0f97 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -20,6 +20,7 @@ ra_db = { path = "../ra_db" } mbe = { path = "../ra_mbe", package = "ra_mbe" } tt = { path = "../ra_tt", package = "ra_tt" } hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } +hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 8eb3c577d671..3f1c36941d03 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -5,6 +5,7 @@ pub(crate) mod docs; use std::sync::Arc; +use hir_def::{CrateModuleId, ModuleId}; use ra_db::{CrateId, Edition, FileId}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; @@ -23,7 +24,7 @@ use crate::{ BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, U32, U64, U8, USIZE, }, - nameres::{CrateModuleId, ImportId, ModuleScope, Namespace}, + nameres::{ImportId, ModuleScope, Namespace}, resolve::{Resolver, Scope, TypeNs}, traits::TraitData, ty::{ @@ -67,8 +68,7 @@ impl Crate { pub fn root_module(self, db: &impl DefDatabase) -> Option { let module_id = db.crate_def_map(self).root(); - let module = Module { krate: self, module_id }; - Some(module) + Some(Module::new(self, module_id)) } pub fn edition(self, db: &impl DefDatabase) -> Edition { @@ -83,8 +83,7 @@ impl Crate { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Module { - pub(crate) krate: Crate, - pub(crate) module_id: CrateModuleId, + pub(crate) id: ModuleId, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -175,12 +174,16 @@ impl ModuleSource { } impl Module { + pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module { + Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } } + } + /// Name of this module. pub fn name(self, db: &impl DefDatabase) -> Option { - let def_map = db.crate_def_map(self.krate); - let parent = def_map[self.module_id].parent?; + let def_map = db.crate_def_map(self.krate()); + let parent = def_map[self.id.module_id].parent?; def_map[parent].children.iter().find_map(|(name, module_id)| { - if *module_id == self.module_id { + if *module_id == self.id.module_id { Some(name.clone()) } else { None @@ -200,29 +203,29 @@ impl Module { } /// Returns the crate this module is part of. - pub fn krate(self, _db: &impl DefDatabase) -> Option { - Some(self.krate) + pub fn krate(self) -> Crate { + Crate { crate_id: self.id.krate } } /// Topmost parent of this module. Every module has a `crate_root`, but some /// might be missing `krate`. This can happen if a module's file is not included /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &impl DefDatabase) -> Module { - let def_map = db.crate_def_map(self.krate); + let def_map = db.crate_def_map(self.krate()); self.with_module_id(def_map.root()) } /// Finds a child module with the specified name. pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option { - let def_map = db.crate_def_map(self.krate); - let child_id = def_map[self.module_id].children.get(name)?; + let def_map = db.crate_def_map(self.krate()); + let child_id = def_map[self.id.module_id].children.get(name)?; Some(self.with_module_id(*child_id)) } /// Iterates over all child modules. pub fn children(self, db: &impl DefDatabase) -> impl Iterator { - let def_map = db.crate_def_map(self.krate); - let children = def_map[self.module_id] + let def_map = db.crate_def_map(self.krate()); + let children = def_map[self.id.module_id] .children .iter() .map(|(_, module_id)| self.with_module_id(*module_id)) @@ -232,8 +235,8 @@ impl Module { /// Finds a parent module. pub fn parent(self, db: &impl DefDatabase) -> Option { - let def_map = db.crate_def_map(self.krate); - let parent_id = def_map[self.module_id].parent?; + let def_map = db.crate_def_map(self.krate()); + let parent_id = def_map[self.id.module_id].parent?; Some(self.with_module_id(parent_id)) } @@ -249,11 +252,11 @@ impl Module { /// Returns a `ModuleScope`: a set of items, visible in this module. pub fn scope(self, db: &impl HirDatabase) -> ModuleScope { - db.crate_def_map(self.krate)[self.module_id].scope.clone() + db.crate_def_map(self.krate())[self.id.module_id].scope.clone() } pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { - db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink); + db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink); for decl in self.declarations(db) { match decl { crate::ModuleDef::Function(f) => f.diagnostics(db, sink), @@ -277,13 +280,13 @@ impl Module { } pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { - let def_map = db.crate_def_map(self.krate); - Resolver::default().push_module_scope(def_map, self.module_id) + let def_map = db.crate_def_map(self.krate()); + Resolver::default().push_module_scope(def_map, self.id.module_id) } pub fn declarations(self, db: &impl DefDatabase) -> Vec { - let def_map = db.crate_def_map(self.krate); - def_map[self.module_id] + let def_map = db.crate_def_map(self.krate()); + def_map[self.id.module_id] .scope .entries() .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None }) @@ -303,7 +306,7 @@ impl Module { } fn with_module_id(self, module_id: CrateModuleId) -> Module { - Module { module_id, krate: self.krate } + Module::new(self.krate(), module_id) } } @@ -344,7 +347,7 @@ impl Struct { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } pub fn name(self, db: &impl DefDatabase) -> Option { @@ -432,7 +435,7 @@ impl Enum { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } pub fn name(self, db: &impl DefDatabase) -> Option { @@ -523,12 +526,14 @@ impl Adt { } pub fn krate(self, db: &impl HirDatabase) -> Option { - match self { - Adt::Struct(s) => s.module(db), - Adt::Union(s) => s.module(db), - Adt::Enum(e) => e.module(db), - } - .krate(db) + Some( + match self { + Adt::Struct(s) => s.module(db), + Adt::Union(s) => s.module(db), + Adt::Enum(e) => e.module(db), + } + .krate(), + ) } pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { @@ -696,7 +701,7 @@ impl Function { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } pub fn name(self, db: &impl HirDatabase) -> Name { @@ -774,7 +779,7 @@ impl Const { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } pub fn data(self, db: &impl HirDatabase) -> Arc { @@ -871,7 +876,7 @@ impl Static { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } pub fn data(self, db: &impl HirDatabase) -> Arc { @@ -1002,7 +1007,7 @@ impl TypeAlias { } pub fn krate(self, db: &impl DefDatabase) -> Option { - self.module(db).krate(db) + Some(self.module(db).krate()) } /// The containing impl block, if this is a method. diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index fdae269060e0..8b33f25f7af8 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -37,9 +37,9 @@ impl Source { impl Module { /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - let def_map = db.crate_def_map(self.krate); - let decl_id = def_map[self.module_id].declaration; - let file_id = def_map[self.module_id].definition; + let def_map = db.crate_def_map(self.krate()); + let decl_id = def_map[self.id.module_id].declaration; + let file_id = def_map[self.id.module_id].definition; let ast = ModuleSource::new(db, file_id, decl_id); let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); Source { file_id, ast } @@ -51,8 +51,8 @@ impl Module { self, db: &(impl DefDatabase + AstDatabase), ) -> Option> { - let def_map = db.crate_def_map(self.krate); - let decl = def_map[self.module_id].declaration?; + let def_map = db.crate_def_map(self.krate()); + let decl = def_map[self.id.module_id].declaration?; let ast = decl.to_node(db); Some(Source { file_id: decl.file_id(), ast }) } diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 7954c04b2e8b..291f2a14ac0e 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -195,7 +195,7 @@ impl Module { .find_map(|krate| { let def_map = db.crate_def_map(krate); let module_id = def_map.find_module_by_source(src.file_id, decl_id)?; - Some(Module { krate, module_id }) + Some(Module::new(krate, module_id)) }) } } diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 1a52236806d6..fde47c264a63 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -182,7 +182,7 @@ impl ModuleImplBlocks { ) -> (Arc, Arc) { let mut source_map = ImplSourceMap::default(); let crate_graph = db.crate_graph(); - let cfg_options = crate_graph.cfg_options(module.krate.crate_id()); + let cfg_options = crate_graph.cfg_options(module.id.krate); let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); (Arc::new(result), Arc::new(source_map)) diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index 6c4e8ffbd3bd..e1780ed388f0 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs @@ -22,14 +22,14 @@ pub enum LangItemTarget { impl LangItemTarget { pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option { - match self { - LangItemTarget::Enum(e) => e.module(db).krate(db), - LangItemTarget::Function(f) => f.module(db).krate(db), - LangItemTarget::ImplBlock(i) => i.module().krate(db), - LangItemTarget::Static(s) => s.module(db).krate(db), - LangItemTarget::Struct(s) => s.module(db).krate(db), - LangItemTarget::Trait(t) => t.module(db).krate(db), - } + Some(match self { + LangItemTarget::Enum(e) => e.module(db).krate(), + LangItemTarget::Function(f) => f.module(db).krate(), + LangItemTarget::ImplBlock(i) => i.module().krate(), + LangItemTarget::Static(s) => s.module(db).krate(), + LangItemTarget::Struct(s) => s.module(db).krate(), + LangItemTarget::Trait(t) => t.module(db).krate(), + }) } } diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 67adcfa2882f..b325979f5b6d 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -56,8 +56,9 @@ mod tests; use std::sync::Arc; +use hir_def::CrateModuleId; use once_cell::sync::Lazy; -use ra_arena::{impl_arena_id, Arena, RawId}; +use ra_arena::Arena; use ra_db::{Edition, FileId}; use ra_prof::profile; use ra_syntax::ast; @@ -115,13 +116,8 @@ impl std::ops::Index for CrateDefMap { } } -/// An ID of a module, **local** to a specific crate -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct CrateModuleId(RawId); -impl_arena_id!(CrateModuleId); - #[derive(Default, Debug, PartialEq, Eq)] -pub(crate) struct ModuleData { +pub struct ModuleData { pub(crate) parent: Option, pub(crate) children: FxHashMap, pub(crate) scope: ModuleScope, @@ -335,7 +331,7 @@ impl CrateDefMap { PathKind::DollarCrate(krate) => { if krate == self.krate { tested_by!(macro_dollar_crate_self); - PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) + PerNs::types(Module::new(self.krate, self.root).into()) } else { match krate.root_module(db) { Some(module) => { @@ -346,12 +342,8 @@ impl CrateDefMap { } } } - PathKind::Crate => { - PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) - } - PathKind::Self_ => { - PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) - } + PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()), + PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()), // plain import or absolute path in 2015: crate-relative with // fallback to extern prelude (with the simplification in // rust-lang/rust#57745) @@ -377,7 +369,7 @@ impl CrateDefMap { } PathKind::Super => { if let Some(p) = self.modules[original_module].parent { - PerNs::types(Module { krate: self.krate, module_id: p }.into()) + PerNs::types(Module::new(self.krate, p).into()) } else { log::debug!("super path in root module"); return ResolvePathResult::empty(ReachedFixedPoint::Yes); @@ -419,12 +411,12 @@ impl CrateDefMap { curr_per_ns = match curr { ModuleDef::Module(module) => { - if module.krate != self.krate { + if module.krate() != self.krate { let path = Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; log::debug!("resolving {:?} in other crate", path); - let defp_map = db.crate_def_map(module.krate); - let (def, s) = defp_map.resolve_path(db, module.module_id, &path); + let defp_map = db.crate_def_map(module.krate()); + let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path); return ResolvePathResult::with( def, ReachedFixedPoint::Yes, @@ -433,7 +425,7 @@ impl CrateDefMap { } // Since it is a qualified path here, it should not contains legacy macros - match self[module.module_id].scope.get(&segment.name) { + match self[module.id.module_id].scope.get(&segment.name) { Some(res) => res.def, _ => { log::debug!("path segment {:?} not found", segment.name); @@ -511,14 +503,14 @@ impl CrateDefMap { fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { if let Some(prelude) = self.prelude { let keep; - let def_map = if prelude.krate == self.krate { + let def_map = if prelude.krate() == self.krate { self } else { // Extend lifetime - keep = db.crate_def_map(prelude.krate); + keep = db.crate_def_map(prelude.krate()); &keep }; - def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) + def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) } else { PerNs::none() } diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index dc591e8d349a..dd5f9d4ba174 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -212,7 +212,7 @@ where if let Some(ModuleDef::Module(m)) = res.take_types() { tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); - self.import_all_macros_exported(current_module_id, m.krate); + self.import_all_macros_exported(current_module_id, m.krate()); } } @@ -289,11 +289,11 @@ where if import.is_prelude { tested_by!(std_prelude); self.def_map.prelude = Some(m); - } else if m.krate != self.def_map.krate { + } else if m.krate() != self.def_map.krate { tested_by!(glob_across_crates); // glob import from other crate => we can just import everything once - let item_map = self.db.crate_def_map(m.krate); - let scope = &item_map[m.module_id].scope; + let item_map = self.db.crate_def_map(m.krate()); + let scope = &item_map[m.id.module_id].scope; // Module scoped macros is included let items = scope @@ -307,7 +307,7 @@ where // glob import from same crate => we do an initial // import, and then need to propagate any further // additions - let scope = &self.def_map[m.module_id].scope; + let scope = &self.def_map[m.id.module_id].scope; // Module scoped macros is included let items = scope @@ -319,7 +319,7 @@ where self.update(module_id, Some(import_id), &items); // record the glob import in case we add further items self.glob_imports - .entry(m.module_id) + .entry(m.id.module_id) .or_default() .push((module_id, import_id)); } @@ -523,9 +523,10 @@ where // Prelude module is always considered to be `#[macro_use]`. if let Some(prelude_module) = self.def_collector.def_map.prelude { - if prelude_module.krate != self.def_collector.def_map.krate { + if prelude_module.krate() != self.def_collector.def_map.krate { tested_by!(prelude_is_macro_use); - self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); + self.def_collector + .import_all_macros_exported(self.module_id, prelude_module.krate()); } } @@ -631,9 +632,7 @@ where modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); modules[self.module_id].children.insert(name.clone(), res); let resolution = Resolution { - def: PerNs::types( - Module { krate: self.def_collector.def_map.krate, module_id: res }.into(), - ), + def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()), import: None, }; self.def_collector.update(self.module_id, None, &[(name, resolution)]); @@ -641,7 +640,7 @@ where } fn define_def(&mut self, def: &raw::DefData) { - let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; + let module = Module::new(self.def_collector.def_map.krate, self.module_id); let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); macro_rules! def { diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3c797c0c3a82..8b62694075df 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -1,6 +1,7 @@ //! Name resolution. use std::sync::Arc; +use hir_def::CrateModuleId; use rustc_hash::FxHashSet; use crate::{ @@ -13,7 +14,7 @@ use crate::{ generics::GenericParams, impl_block::ImplBlock, name::{Name, SELF_PARAM, SELF_TYPE}, - nameres::{CrateDefMap, CrateModuleId, PerNs}, + nameres::{CrateDefMap, PerNs}, path::{Path, PathKind}, Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, @@ -330,8 +331,8 @@ impl Resolver { for scope in &self.scopes { if let Scope::ModuleScope(m) = scope { if let Some(prelude) = m.crate_def_map.prelude() { - let prelude_def_map = db.crate_def_map(prelude.krate); - traits.extend(prelude_def_map[prelude.module_id].scope.traits()); + let prelude_def_map = db.crate_def_map(prelude.krate()); + traits.extend(prelude_def_map[prelude.id.module_id].scope.traits()); } traits.extend(m.crate_def_map[m.module_id].scope.traits()); } @@ -444,10 +445,12 @@ impl Scope { f(name.clone(), ScopeDef::ModuleDef(*def)); }); if let Some(prelude) = m.crate_def_map.prelude() { - let prelude_def_map = db.crate_def_map(prelude.krate); - prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { - f(name.clone(), res.def.into()); - }); + let prelude_def_map = db.crate_def_map(prelude.krate()); + prelude_def_map[prelude.id.module_id].scope.entries().for_each( + |(name, res)| { + f(name.clone(), res.def.into()); + }, + ); } } Scope::GenericParams(gp) => { diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index ad2ab560d8e5..50583a1429e6 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -5,13 +5,13 @@ use std::sync::Arc; use arrayvec::ArrayVec; +use hir_def::CrateModuleId; use rustc_hash::FxHashMap; use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; use crate::{ db::HirDatabase, impl_block::{ImplBlock, ImplId}, - nameres::CrateModuleId, resolve::Resolver, ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, ty::{Ty, TypeCtor}, @@ -50,7 +50,7 @@ impl CrateImplBlocks { let fingerprint = TyFingerprint::for_impl(ty); fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map( move |(module_id, impl_id)| { - let module = Module { krate: self.krate, module_id: *module_id }; + let module = Module::new(self.krate, *module_id); ImplBlock::from_id(module, *impl_id) }, ) @@ -62,7 +62,7 @@ impl CrateImplBlocks { ) -> impl Iterator + 'a { self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( move |(module_id, impl_id)| { - let module = Module { krate: self.krate, module_id: *module_id }; + let module = Module::new(self.krate, *module_id); ImplBlock::from_id(module, *impl_id) }, ) @@ -71,7 +71,7 @@ impl CrateImplBlocks { pub fn all_impls<'a>(&'a self) -> impl Iterator + 'a { self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map( move |(module_id, impl_id)| { - let module = Module { krate: self.krate, module_id: *module_id }; + let module = Module::new(self.krate, *module_id); ImplBlock::from_id(module, *impl_id) }, ) @@ -90,14 +90,14 @@ impl CrateImplBlocks { self.impls_by_trait .entry(tr.trait_) .or_insert_with(Vec::new) - .push((module.module_id, impl_id)); + .push((module.id.module_id, impl_id)); } } else { if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { self.impls .entry(target_ty_fp) .or_insert_with(Vec::new) - .push((module.module_id, impl_id)); + .push((module.id.module_id, impl_id)); } } } diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index e18c28cf6386..aec484feb23b 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -537,7 +537,7 @@ pub(crate) fn trait_datum_query( let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db); let flags = chalk_rust_ir::TraitFlags { auto: trait_.is_auto(db), - upstream: trait_.module(db).krate(db) != Some(krate), + upstream: trait_.module(db).krate() != krate, non_enumerable: true, // FIXME set these flags correctly marker: false, @@ -625,7 +625,7 @@ fn impl_block_datum( .target_trait_ref(db) .expect("FIXME handle unresolved impl block trait ref") .subst(&bound_vars); - let impl_type = if impl_block.module().krate(db) == Some(krate) { + let impl_type = if impl_block.module().krate() == krate { chalk_rust_ir::ImplType::Local } else { chalk_rust_ir::ImplType::External diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml new file mode 100644 index 000000000000..f22a678eb797 --- /dev/null +++ b/crates/ra_hir_def/Cargo.toml @@ -0,0 +1,13 @@ +[package] +edition = "2018" +name = "ra_hir_def" +version = "0.1.0" +authors = ["rust-analyzer developers"] + +[dependencies] +log = "0.4.5" + +ra_arena = { path = "../ra_arena" } +ra_db = { path = "../ra_db" } +ra_syntax = { path = "../ra_syntax" } +ra_prof = { path = "../ra_prof" } diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs new file mode 100644 index 000000000000..f5dd2ae6fbd5 --- /dev/null +++ b/crates/ra_hir_def/src/lib.rs @@ -0,0 +1,14 @@ +use ra_arena::{impl_arena_id, RawId}; +use ra_db::CrateId; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ModuleId { + pub krate: CrateId, + pub module_id: CrateModuleId, +} + +/// An ID of a module, **local** to a specific crate +// FIXME: rename to `LocalModuleId`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct CrateModuleId(RawId); +impl_arena_id!(CrateModuleId); From c9cd6aa370667783292de3bc580e0503a409e453 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 13:10:38 +0300 Subject: [PATCH 079/102] Move ids to hir_def crate --- Cargo.lock | 1 + crates/ra_hir/src/code_model.rs | 16 +- crates/ra_hir/src/code_model/src.rs | 20 +- crates/ra_hir/src/db.rs | 28 +-- crates/ra_hir/src/from_source.rs | 2 +- crates/ra_hir/src/ids.rs | 167 +------------- crates/ra_hir/src/impl_block.rs | 2 +- crates/ra_hir/src/nameres/collector.rs | 2 +- crates/ra_hir/src/source_binder.rs | 2 +- crates/ra_hir/src/traits.rs | 2 +- crates/ra_hir/src/ty/traits/chalk.rs | 34 +-- crates/ra_hir_def/Cargo.toml | 1 + crates/ra_hir_def/src/db.rs | 22 ++ crates/ra_hir_def/src/lib.rs | 204 +++++++++++++++++- .../src/completion/complete_path.rs | 2 +- crates/ra_ide_api/src/impls.rs | 4 +- crates/ra_ide_api/src/parent_module.rs | 5 +- .../ra_ide_api/src/references/search_scope.rs | 2 +- 18 files changed, 258 insertions(+), 258 deletions(-) create mode 100644 crates/ra_hir_def/src/db.rs diff --git a/Cargo.lock b/Cargo.lock index a7643362095b..66ff1285a092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1021,6 +1021,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", "ra_db 0.1.0", + "ra_hir_expand 0.1.0", "ra_prof 0.1.0", "ra_syntax 0.1.0", ] diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 3f1c36941d03..1a790b2f3002 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -343,7 +343,7 @@ pub struct Struct { impl Struct { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -405,7 +405,7 @@ impl Union { } pub fn module(self, db: &impl HirDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn ty(self, db: &impl HirDatabase) -> Ty { @@ -431,7 +431,7 @@ pub struct Enum { impl Enum { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -697,7 +697,7 @@ impl FnData { impl Function { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -775,7 +775,7 @@ pub struct Const { impl Const { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -872,7 +872,7 @@ pub struct Static { impl Static { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { @@ -901,7 +901,7 @@ pub struct Trait { impl Trait { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn name(self, db: &impl DefDatabase) -> Option { @@ -1003,7 +1003,7 @@ pub struct TypeAlias { impl TypeAlias { pub fn module(self, db: &impl DefDatabase) -> Module { - self.id.module(db) + Module { id: self.id.module(db) } } pub fn krate(self, db: &impl DefDatabase) -> Option { diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 8b33f25f7af8..5c7f61eefb46 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -1,9 +1,6 @@ //! FIXME: write short doc here -use ra_syntax::{ - ast::{self, AstNode}, - SyntaxNode, -}; +use ra_syntax::ast::{self, AstNode}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, @@ -12,26 +9,13 @@ use crate::{ ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct Source { - pub file_id: HirFileId, - pub ast: T, -} +pub use hir_def::Source; pub trait HasSource { type Ast; fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source; } -impl Source { - pub(crate) fn map U, U>(self, f: F) -> Source { - Source { file_id: self.file_id, ast: f(self.ast) } - } - pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { - db.parse_or_expand(self.file_id).expect("source created from invalid file") - } -} - /// NB: Module is !HasSource, because it has two source nodes at the same time: /// definition and declaration. impl Module { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index da8ae6ef4741..8f6cb2da7d3c 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -2,8 +2,8 @@ use std::sync::Arc; -use ra_db::{salsa, SourceDatabase}; -use ra_syntax::{ast, SmolStr}; +use ra_db::salsa; +use ra_syntax::SmolStr; use crate::{ adt::{EnumData, StructData}, @@ -23,34 +23,12 @@ use crate::{ Static, Struct, StructField, Trait, TypeAlias, }; +pub use hir_def::db::{InternDatabase, InternDatabaseStorage}; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, }; -/// We store all interned things in the single QueryGroup. -/// -/// This is done mainly to allow both "volatile" `AstDatabase` and "stable" -/// `DefDatabase` to access macros, without adding hard dependencies between the -/// two. -#[salsa::query_group(InternDatabaseStorage)] -pub trait InternDatabase: SourceDatabase { - #[salsa::interned] - fn intern_function(&self, loc: ids::ItemLoc) -> ids::FunctionId; - #[salsa::interned] - fn intern_struct(&self, loc: ids::ItemLoc) -> ids::StructId; - #[salsa::interned] - fn intern_enum(&self, loc: ids::ItemLoc) -> ids::EnumId; - #[salsa::interned] - fn intern_const(&self, loc: ids::ItemLoc) -> ids::ConstId; - #[salsa::interned] - fn intern_static(&self, loc: ids::ItemLoc) -> ids::StaticId; - #[salsa::interned] - fn intern_trait(&self, loc: ids::ItemLoc) -> ids::TraitId; - #[salsa::interned] - fn intern_type_alias(&self, loc: ids::ItemLoc) -> ids::TypeAliasId; -} - // This database uses `AstDatabase` internally, #[salsa::query_group(DefDatabaseStorage)] #[salsa::requires(AstDatabase)] diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 291f2a14ac0e..93713bb1424f 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -208,6 +208,6 @@ where let module_src = crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax()); let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; - let ctx = LocationCtx::new(db, module, src.file_id); + let ctx = LocationCtx::new(db, module.id, src.file_id); Some(DEF::from_ast(ctx, &src.ast)) } diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index dea288eb7bc9..fe083c0c65f6 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -5,16 +5,12 @@ //! This module defines a bunch of ids we are using. The most important ones are //! probably `HirFileId` and `DefId`. -use std::hash::{Hash, Hasher}; - use ra_db::salsa; -use ra_syntax::{ast, AstNode}; -use crate::{ - db::{AstDatabase, InternDatabase}, - AstId, FileAstId, Module, Source, +pub use hir_def::{ + AstItemDef, ConstId, EnumId, FunctionId, ItemLoc, LocationCtx, StaticId, StructId, TraitId, + TypeAliasId, }; - pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind}; macro_rules! impl_intern_key { @@ -30,163 +26,6 @@ macro_rules! impl_intern_key { }; } -#[derive(Debug)] -pub struct ItemLoc { - pub(crate) module: Module, - ast_id: AstId, -} - -impl PartialEq for ItemLoc { - fn eq(&self, other: &Self) -> bool { - self.module == other.module && self.ast_id == other.ast_id - } -} -impl Eq for ItemLoc {} -impl Hash for ItemLoc { - fn hash(&self, hasher: &mut H) { - self.module.hash(hasher); - self.ast_id.hash(hasher); - } -} - -impl Clone for ItemLoc { - fn clone(&self) -> ItemLoc { - ItemLoc { module: self.module, ast_id: self.ast_id } - } -} - -#[derive(Clone, Copy)] -pub(crate) struct LocationCtx { - db: DB, - module: Module, - file_id: HirFileId, -} - -impl<'a, DB> LocationCtx<&'a DB> { - pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { - LocationCtx { db, module, file_id } - } -} - -impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> { - pub(crate) fn to_def(self, ast: &N) -> DEF - where - N: AstNode, - DEF: AstItemDef, - { - DEF::from_ast(self, ast) - } -} - -pub(crate) trait AstItemDef: salsa::InternKey + Clone { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self; - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc; - - fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self { - let items = ctx.db.ast_id_map(ctx.file_id); - let item_id = items.ast_id(ast); - Self::from_ast_id(ctx, item_id) - } - fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId) -> Self { - let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; - Self::intern(ctx.db, loc) - } - fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source { - let loc = self.lookup_intern(db); - let ast = loc.ast_id.to_node(db); - Source { file_id: loc.ast_id.file_id(), ast } - } - fn module(self, db: &impl InternDatabase) -> Module { - let loc = self.lookup_intern(db); - loc.module - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct FunctionId(salsa::InternId); -impl_intern_key!(FunctionId); - -impl AstItemDef for FunctionId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_function(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_function(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct StructId(salsa::InternId); -impl_intern_key!(StructId); -impl AstItemDef for StructId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_struct(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_struct(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct EnumId(salsa::InternId); -impl_intern_key!(EnumId); -impl AstItemDef for EnumId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_enum(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_enum(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct ConstId(salsa::InternId); -impl_intern_key!(ConstId); -impl AstItemDef for ConstId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_const(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_const(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct StaticId(salsa::InternId); -impl_intern_key!(StaticId); -impl AstItemDef for StaticId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_static(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_static(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TraitId(salsa::InternId); -impl_intern_key!(TraitId); -impl AstItemDef for TraitId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_trait(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_trait(self) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct TypeAliasId(salsa::InternId); -impl_intern_key!(TypeAliasId); -impl AstItemDef for TypeAliasId { - fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { - db.intern_type_alias(loc) - } - fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { - db.lookup_intern_type_alias(self) - } -} - /// This exists just for Chalk, because Chalk just has a single `StructId` where /// we have different kinds of ADTs, primitive types and special type /// constructors like tuples and function pointers. diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index fde47c264a63..06f21fc33eee 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -129,7 +129,7 @@ impl ImplData { ) -> Self { let target_trait = node.target_trait().map(TypeRef::from_ast); let target_type = TypeRef::from_ast_opt(node.target_type()); - let ctx = LocationCtx::new(db, module, file_id); + let ctx = LocationCtx::new(db, module.id, file_id); let negative = node.is_negative(); let items = if let Some(item_list) = node.item_list() { item_list diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index dd5f9d4ba174..a94a0554c84c 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -641,7 +641,7 @@ where fn define_def(&mut self, def: &raw::DefData) { let module = Module::new(self.def_collector.def_map.krate, self.module_id); - let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); + let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id); macro_rules! def { ($kind:ident, $ast_id:ident) => { diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index a907d6a9f9db..730c3322647e 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -64,7 +64,7 @@ fn def_with_body_from_child_node( ) -> Option { let src = crate::ModuleSource::from_child_node(db, file_id, node); let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?; - let ctx = LocationCtx::new(db, module, file_id.into()); + let ctx = LocationCtx::new(db, module.id, file_id.into()); node.ancestors().find_map(|node| { if let Some(def) = ast::FnDef::cast(node.clone()) { diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs index e39511518d10..22f1880493f9 100644 --- a/crates/ra_hir/src/traits.rs +++ b/crates/ra_hir/src/traits.rs @@ -27,7 +27,7 @@ impl TraitData { let src = tr.source(db); let name = src.ast.name().map(|n| n.as_name()); let module = tr.module(db); - let ctx = LocationCtx::new(db, module, src.file_id); + let ctx = LocationCtx::new(db, module.id, src.file_id); let auto = src.ast.is_auto(); let items = if let Some(item_list) = src.ast.item_list() { item_list diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index aec484feb23b..ab66515beecf 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -162,11 +162,11 @@ impl ToChalk for Trait { type Chalk = chalk_ir::TraitId; fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { - self.id.into() + chalk_ir::TraitId(id_to_chalk(self.id)) } fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait { - Trait { id: trait_id.into() } + Trait { id: id_from_chalk(trait_id.0) } } } @@ -198,11 +198,11 @@ impl ToChalk for TypeAlias { type Chalk = chalk_ir::TypeId; fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { - self.id.into() + chalk_ir::TypeId(id_to_chalk(self.id)) } - fn from_chalk(_db: &impl HirDatabase, impl_id: chalk_ir::TypeId) -> TypeAlias { - TypeAlias { id: impl_id.into() } + fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAlias { + TypeAlias { id: id_from_chalk(type_alias_id.0) } } } @@ -775,30 +775,6 @@ fn id_to_chalk(salsa_id: T) -> chalk_ir::RawId { chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } } -impl From for crate::ids::TraitId { - fn from(trait_id: chalk_ir::TraitId) -> Self { - id_from_chalk(trait_id.0) - } -} - -impl From for chalk_ir::TraitId { - fn from(trait_id: crate::ids::TraitId) -> Self { - chalk_ir::TraitId(id_to_chalk(trait_id)) - } -} - -impl From for crate::ids::TypeAliasId { - fn from(type_id: chalk_ir::TypeId) -> Self { - id_from_chalk(type_id.0) - } -} - -impl From for chalk_ir::TypeId { - fn from(type_id: crate::ids::TypeAliasId) -> Self { - chalk_ir::TypeId(id_to_chalk(type_id)) - } -} - impl From for crate::ids::TypeCtorId { fn from(struct_id: chalk_ir::StructId) -> Self { id_from_chalk(struct_id.0) diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index f22a678eb797..75e93f2547bb 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -11,3 +11,4 @@ ra_arena = { path = "../ra_arena" } ra_db = { path = "../ra_db" } ra_syntax = { path = "../ra_syntax" } ra_prof = { path = "../ra_prof" } +hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs new file mode 100644 index 000000000000..f6f976c860a0 --- /dev/null +++ b/crates/ra_hir_def/src/db.rs @@ -0,0 +1,22 @@ +//! Defines database & queries for name resolution. + +use ra_db::{salsa, SourceDatabase}; +use ra_syntax::ast; + +#[salsa::query_group(InternDatabaseStorage)] +pub trait InternDatabase: SourceDatabase { + #[salsa::interned] + fn intern_function(&self, loc: crate::ItemLoc) -> crate::FunctionId; + #[salsa::interned] + fn intern_struct(&self, loc: crate::ItemLoc) -> crate::StructId; + #[salsa::interned] + fn intern_enum(&self, loc: crate::ItemLoc) -> crate::EnumId; + #[salsa::interned] + fn intern_const(&self, loc: crate::ItemLoc) -> crate::ConstId; + #[salsa::interned] + fn intern_static(&self, loc: crate::ItemLoc) -> crate::StaticId; + #[salsa::interned] + fn intern_trait(&self, loc: crate::ItemLoc) -> crate::TraitId; + #[salsa::interned] + fn intern_type_alias(&self, loc: crate::ItemLoc) -> crate::TypeAliasId; +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index f5dd2ae6fbd5..4d6b9db033f9 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -1,5 +1,37 @@ +//! `hir_def` crate contains everything between macro expansion and type +//! inference. +//! +//! It defines various items (structs, enums, traits) which comprises Rust code, +//! as well as an algorithm for resolving paths to such entities. +//! +//! Note that `hir_def` is a work in progress, so not all of the above is +//! actually true. + +pub mod db; + +use std::hash::{Hash, Hasher}; + +use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; use ra_arena::{impl_arena_id, RawId}; -use ra_db::CrateId; +use ra_db::{salsa, CrateId}; +use ra_syntax::{ast, AstNode, SyntaxNode}; + +use crate::db::InternDatabase; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Source { + pub file_id: HirFileId, + pub ast: T, +} + +impl Source { + pub fn map U, U>(self, f: F) -> Source { + Source { file_id: self.file_id, ast: f(self.ast) } + } + pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { + db.parse_or_expand(self.file_id).expect("source created from invalid file") + } +} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ModuleId { @@ -12,3 +44,173 @@ pub struct ModuleId { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct CrateModuleId(RawId); impl_arena_id!(CrateModuleId); + +macro_rules! impl_intern_key { + ($name:ident) => { + impl salsa::InternKey for $name { + fn from_intern_id(v: salsa::InternId) -> Self { + $name(v) + } + fn as_intern_id(&self) -> salsa::InternId { + self.0 + } + } + }; +} + +#[derive(Debug)] +pub struct ItemLoc { + pub(crate) module: ModuleId, + ast_id: AstId, +} + +impl PartialEq for ItemLoc { + fn eq(&self, other: &Self) -> bool { + self.module == other.module && self.ast_id == other.ast_id + } +} +impl Eq for ItemLoc {} +impl Hash for ItemLoc { + fn hash(&self, hasher: &mut H) { + self.module.hash(hasher); + self.ast_id.hash(hasher); + } +} + +impl Clone for ItemLoc { + fn clone(&self) -> ItemLoc { + ItemLoc { module: self.module, ast_id: self.ast_id } + } +} + +#[derive(Clone, Copy)] +pub struct LocationCtx { + db: DB, + module: ModuleId, + file_id: HirFileId, +} + +impl<'a, DB> LocationCtx<&'a DB> { + pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { + LocationCtx { db, module, file_id } + } +} + +impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> { + pub fn to_def(self, ast: &N) -> DEF + where + N: AstNode, + DEF: AstItemDef, + { + DEF::from_ast(self, ast) + } +} + +pub trait AstItemDef: salsa::InternKey + Clone { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self; + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc; + + fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self { + let items = ctx.db.ast_id_map(ctx.file_id); + let item_id = items.ast_id(ast); + Self::from_ast_id(ctx, item_id) + } + fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId) -> Self { + let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; + Self::intern(ctx.db, loc) + } + fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source { + let loc = self.lookup_intern(db); + let ast = loc.ast_id.to_node(db); + Source { file_id: loc.ast_id.file_id(), ast } + } + fn module(self, db: &impl InternDatabase) -> ModuleId { + let loc = self.lookup_intern(db); + loc.module + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct FunctionId(salsa::InternId); +impl_intern_key!(FunctionId); + +impl AstItemDef for FunctionId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_function(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_function(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StructId(salsa::InternId); +impl_intern_key!(StructId); +impl AstItemDef for StructId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_struct(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_struct(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumId(salsa::InternId); +impl_intern_key!(EnumId); +impl AstItemDef for EnumId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_enum(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_enum(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ConstId(salsa::InternId); +impl_intern_key!(ConstId); +impl AstItemDef for ConstId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_const(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_const(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StaticId(salsa::InternId); +impl_intern_key!(StaticId); +impl AstItemDef for StaticId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_static(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_static(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TraitId(salsa::InternId); +impl_intern_key!(TraitId); +impl AstItemDef for TraitId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_trait(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_trait(self) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TypeAliasId(salsa::InternId); +impl_intern_key!(TypeAliasId); +impl AstItemDef for TypeAliasId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_type_alias(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_type_alias(self) + } +} diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 23dece73c2fa..956d8ce49c44 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -50,7 +50,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), _ => unreachable!(), }; - let krate = ctx.module.and_then(|m| m.krate(ctx.db)); + let krate = ctx.module.map(|m| m.krate()); if let Some(krate) = krate { ty.iterate_impl_items(ctx.db, krate, |item| { match item { diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index 7fc1b1efa88d..b899ed3a5f78 100644 --- a/crates/ra_ide_api/src/impls.rs +++ b/crates/ra_ide_api/src/impls.rs @@ -51,7 +51,7 @@ fn impls_for_def( } }; - let krate = module.krate(db)?; + let krate = module.krate(); let impls = db.impls_in_crate(krate); Some( @@ -72,7 +72,7 @@ fn impls_for_trait( let src = hir::Source { file_id: position.file_id.into(), ast: node.clone() }; let tr = hir::Trait::from_source(db, src)?; - let krate = module.krate(db)?; + let krate = module.krate(); let impls = db.impls_in_crate(krate); Some( diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs index 56650984995b..4c57566e2af9 100644 --- a/crates/ra_ide_api/src/parent_module.rs +++ b/crates/ra_ide_api/src/parent_module.rs @@ -27,10 +27,7 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec { Some(it) => it, None => return Vec::new(), }; - let krate = match module.krate(db) { - Some(it) => it, - None => return Vec::new(), - }; + let krate = module.krate(); vec![krate.crate_id()] } diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index b6eb248b742b..dbd1af597693 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -120,7 +120,7 @@ impl NameDefinition { return SearchScope::new(res); } if vis.as_str() == "pub" { - let krate = self.container.krate(db).unwrap(); + let krate = self.container.krate(); let crate_graph = db.crate_graph(); for crate_id in crate_graph.iter() { let mut crate_deps = crate_graph.dependencies(crate_id); From 16e620c052016010b2f17070a98bdc1e7e849ab3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 16:12:55 +0300 Subject: [PATCH 080/102] move raw_items to hir_def --- Cargo.lock | 7 + crates/ra_hir/src/attr.rs | 91 +--- crates/ra_hir/src/code_model.rs | 30 +- crates/ra_hir/src/db.rs | 17 +- crates/ra_hir/src/either.rs | 55 +-- crates/ra_hir/src/from_source.rs | 42 +- crates/ra_hir/src/lib.rs | 5 +- crates/ra_hir/src/marks.rs | 1 + crates/ra_hir/src/mock.rs | 1 + crates/ra_hir/src/name.rs | 143 +----- crates/ra_hir/src/nameres.rs | 11 +- crates/ra_hir/src/nameres/collector.rs | 3 +- .../src/nameres/tests/mod_resolution.rs | 2 +- crates/ra_hir/src/path.rs | 423 +----------------- crates/ra_hir/src/type_ref.rs | 163 +------ crates/ra_hir_def/Cargo.toml | 7 + crates/ra_hir_def/src/attr.rs | 91 ++++ crates/ra_hir_def/src/db.rs | 18 + crates/ra_hir_def/src/either.rs | 54 +++ crates/ra_hir_def/src/lib.rs | 95 +++- crates/ra_hir_def/src/name.rs | 142 ++++++ crates/ra_hir_def/src/nameres.rs | 1 + .../{ra_hir => ra_hir_def}/src/nameres/raw.rs | 62 +-- crates/ra_hir_def/src/path.rs | 423 ++++++++++++++++++ crates/ra_hir_def/src/type_ref.rs | 162 +++++++ crates/ra_hir_expand/src/lib.rs | 8 +- 26 files changed, 1059 insertions(+), 998 deletions(-) create mode 100644 crates/ra_hir_def/src/attr.rs create mode 100644 crates/ra_hir_def/src/either.rs create mode 100644 crates/ra_hir_def/src/name.rs create mode 100644 crates/ra_hir_def/src/nameres.rs rename crates/{ra_hir => ra_hir_def}/src/nameres/raw.rs (91%) create mode 100644 crates/ra_hir_def/src/path.rs create mode 100644 crates/ra_hir_def/src/type_ref.rs diff --git a/Cargo.lock b/Cargo.lock index 66ff1285a092..fdacd82a70e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1019,11 +1019,18 @@ name = "ra_hir_def" version = "0.1.0" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", + "ra_cfg 0.1.0", "ra_db 0.1.0", "ra_hir_expand 0.1.0", + "ra_mbe 0.1.0", "ra_prof 0.1.0", "ra_syntax 0.1.0", + "ra_tt 0.1.0", + "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "test_utils 0.1.0", ] [[package]] diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs index bd159a56650c..988a671b81b2 100644 --- a/crates/ra_hir/src/attr.rs +++ b/crates/ra_hir/src/attr.rs @@ -1,90 +1 @@ -//! A higher level attributes based on TokenTree, with also some shortcuts. - -use std::sync::Arc; - -use mbe::ast_to_token_tree; -use ra_cfg::CfgOptions; -use ra_syntax::{ - ast::{self, AstNode, AttrsOwner}, - SmolStr, -}; -use tt::Subtree; - -use crate::{db::AstDatabase, path::Path, HirFileId, Source}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct Attr { - pub(crate) path: Path, - pub(crate) input: Option, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum AttrInput { - Literal(SmolStr), - TokenTree(Subtree), -} - -impl Attr { - pub(crate) fn from_src( - Source { file_id, ast }: Source, - db: &impl AstDatabase, - ) -> Option { - let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?; - let input = match ast.input() { - None => None, - Some(ast::AttrInput::Literal(lit)) => { - // FIXME: escape? raw string? - let value = lit.syntax().first_token()?.text().trim_matches('"').into(); - Some(AttrInput::Literal(value)) - } - Some(ast::AttrInput::TokenTree(tt)) => { - Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) - } - }; - - Some(Attr { path, input }) - } - - pub(crate) fn from_attrs_owner( - file_id: HirFileId, - owner: &dyn AttrsOwner, - db: &impl AstDatabase, - ) -> Option> { - let mut attrs = owner.attrs().peekable(); - if attrs.peek().is_none() { - // Avoid heap allocation - return None; - } - Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) - } - - pub(crate) fn is_simple_atom(&self, name: &str) -> bool { - // FIXME: Avoid cloning - self.path.as_ident().map_or(false, |s| s.to_string() == name) - } - - // FIXME: handle cfg_attr :-) - pub(crate) fn as_cfg(&self) -> Option<&Subtree> { - if !self.is_simple_atom("cfg") { - return None; - } - match &self.input { - Some(AttrInput::TokenTree(subtree)) => Some(subtree), - _ => None, - } - } - - pub(crate) fn as_path(&self) -> Option<&SmolStr> { - if !self.is_simple_atom("path") { - return None; - } - match &self.input { - Some(AttrInput::Literal(it)) => Some(it), - _ => None, - } - } - - pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option { - cfg_options.is_cfg_enabled(self.as_cfg()?) - } -} +pub use hir_def::attr::*; diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 1a790b2f3002..de1377aa45ab 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -6,7 +6,7 @@ pub(crate) mod docs; use std::sync::Arc; use hir_def::{CrateModuleId, ModuleId}; -use ra_db::{CrateId, Edition, FileId}; +use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ @@ -33,7 +33,7 @@ use crate::{ }, type_ref::Mutability, type_ref::TypeRef, - AsName, AstId, Either, HasSource, Name, Ty, + AsName, Either, HasSource, Name, Ty, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -147,31 +147,7 @@ impl_froms!( BuiltinType ); -pub enum ModuleSource { - SourceFile(ast::SourceFile), - Module(ast::Module), -} - -impl ModuleSource { - pub(crate) fn new( - db: &(impl DefDatabase + AstDatabase), - file_id: Option, - decl_id: Option>, - ) -> ModuleSource { - match (file_id, decl_id) { - (Some(file_id), _) => { - let source_file = db.parse(file_id).tree(); - ModuleSource::SourceFile(source_file) - } - (None, Some(item_id)) => { - let module = item_id.to_node(db); - assert!(module.item_list().is_some(), "expected inline module"); - ModuleSource::Module(module) - } - (None, None) => panic!(), - } - } -} +pub use hir_def::ModuleSource; impl Module { pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 8f6cb2da7d3c..142d7338df8d 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -12,15 +12,15 @@ use crate::{ ids, impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, lang_item::{LangItemTarget, LangItems}, - nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems}, + nameres::{CrateDefMap, Namespace}, traits::TraitData, ty::{ method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, Ty, TypableDef, TypeCtor, }, type_alias::TypeAliasData, - Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, HirFileId, Module, - Static, Struct, StructField, Trait, TypeAlias, + Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, Module, Static, + Struct, StructField, Trait, TypeAlias, }; pub use hir_def::db::{InternDatabase, InternDatabaseStorage}; @@ -32,7 +32,7 @@ pub use hir_expand::db::{ // This database uses `AstDatabase` internally, #[salsa::query_group(DefDatabaseStorage)] #[salsa::requires(AstDatabase)] -pub trait DefDatabase: InternDatabase + HirDebugDatabase + AstDatabase { +pub trait DefDatabase: HirDebugDatabase + hir_def::db::DefDatabase2 { #[salsa::invoke(crate::adt::StructData::struct_data_query)] fn struct_data(&self, s: Struct) -> Arc; @@ -45,15 +45,6 @@ pub trait DefDatabase: InternDatabase + HirDebugDatabase + AstDatabase { #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; - #[salsa::invoke(RawItems::raw_items_with_source_map_query)] - fn raw_items_with_source_map( - &self, - file_id: HirFileId, - ) -> (Arc, Arc); - - #[salsa::invoke(RawItems::raw_items_query)] - fn raw_items(&self, file_id: HirFileId) -> Arc; - #[salsa::invoke(CrateDefMap::crate_def_map_query)] fn crate_def_map(&self, krate: Crate) -> Arc; diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs index 83583ef8bd3c..44498dd388c4 100644 --- a/crates/ra_hir/src/either.rs +++ b/crates/ra_hir/src/either.rs @@ -1,54 +1 @@ -//! FIXME: write short doc here - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Either { - A(A), - B(B), -} - -impl Either { - pub fn either(self, f1: F1, f2: F2) -> R - where - F1: FnOnce(A) -> R, - F2: FnOnce(B) -> R, - { - match self { - Either::A(a) => f1(a), - Either::B(b) => f2(b), - } - } - pub fn map(self, f1: F1, f2: F2) -> Either - where - F1: FnOnce(A) -> U, - F2: FnOnce(B) -> V, - { - match self { - Either::A(a) => Either::A(f1(a)), - Either::B(b) => Either::B(f2(b)), - } - } - pub fn map_a(self, f: F) -> Either - where - F: FnOnce(A) -> U, - { - self.map(f, |it| it) - } - pub fn a(self) -> Option { - match self { - Either::A(it) => Some(it), - Either::B(_) => None, - } - } - pub fn b(self) -> Option { - match self { - Either::A(_) => None, - Either::B(it) => Some(it), - } - } - pub fn as_ref(&self) -> Either<&A, &B> { - match self { - Either::A(it) => Either::A(it), - Either::B(it) => Either::B(it), - } - } -} +pub use hir_def::either::*; diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 93713bb1424f..697c8dc8490f 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -1,11 +1,6 @@ //! FIXME: write short doc here -use ra_db::{FileId, FilePosition}; -use ra_syntax::{ - algo::find_node_at_offset, - ast::{self, AstNode, NameOwner}, - SyntaxNode, -}; +use ra_syntax::ast::{self, AstNode, NameOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, @@ -129,41 +124,6 @@ impl FromSource for StructField { } } -// FIXME: simplify it -impl ModuleSource { - pub fn from_position( - db: &(impl DefDatabase + AstDatabase), - position: FilePosition, - ) -> ModuleSource { - let parse = db.parse(position.file_id); - match &find_node_at_offset::(parse.tree().syntax(), position.offset) { - Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()), - _ => { - let source_file = parse.tree(); - ModuleSource::SourceFile(source_file) - } - } - } - - pub fn from_child_node( - db: &(impl DefDatabase + AstDatabase), - file_id: FileId, - child: &SyntaxNode, - ) -> ModuleSource { - if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) { - ModuleSource::Module(m) - } else { - let source_file = db.parse(file_id).tree(); - ModuleSource::SourceFile(source_file) - } - } - - pub fn from_file_id(db: &(impl DefDatabase + AstDatabase), file_id: FileId) -> ModuleSource { - let source_file = db.parse(file_id).tree(); - ModuleSource::SourceFile(source_file) - } -} - impl Module { pub fn from_declaration(db: &impl HirDatabase, src: Source) -> Option { let src_parent = Source { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 0f2d233bb1b9..b49f615bf351 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -59,10 +59,7 @@ pub mod from_source; #[cfg(test)] mod marks; -use hir_expand::{ - ast_id_map::{AstIdMap, FileAstId}, - AstId, -}; +use hir_expand::AstId; use crate::{ids::MacroFileKind, name::AsName, resolve::Resolver}; diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 79af24b201a1..b423489a1117 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -2,6 +2,7 @@ test_utils::marks!( bogus_paths + // FIXME: restore this mark once hir is split name_res_works_for_broken_modules can_import_enum_variant type_var_cycles_resolve_completely diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 0b278deb3ae3..bb2d78abe2f0 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -17,6 +17,7 @@ use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; pub const WORKSPACE: SourceRootId = SourceRootId(0); #[salsa::database( + hir_def::db::DefDatabase2Storage, ra_db::SourceDatabaseExtStorage, ra_db::SourceDatabaseStorage, db::InternDatabaseStorage, diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 1e0b8c3506ff..cf66f88adf7a 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs @@ -1,142 +1 @@ -//! FIXME: write short doc here - -use std::fmt; - -use ra_syntax::{ast, SmolStr}; - -/// `Name` is a wrapper around string, which is used in hir for both references -/// and declarations. In theory, names should also carry hygiene info, but we are -/// not there yet! -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Name(Repr); - -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -enum Repr { - Text(SmolStr), - TupleField(usize), -} - -impl fmt::Display for Name { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match &self.0 { - Repr::Text(text) => fmt::Display::fmt(&text, f), - Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), - } - } -} - -impl Name { - /// Note: this is private to make creating name from random string hard. - /// Hopefully, this should allow us to integrate hygiene cleaner in the - /// future, and to switch to interned representation of names. - const fn new_text(text: SmolStr) -> Name { - Name(Repr::Text(text)) - } - - pub(crate) fn new_tuple_field(idx: usize) -> Name { - Name(Repr::TupleField(idx)) - } - - /// Shortcut to create inline plain text name - const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { - Name::new_text(SmolStr::new_inline_from_ascii(len, text)) - } - - /// Resolve a name from the text of token. - fn resolve(raw_text: &SmolStr) -> Name { - let raw_start = "r#"; - if raw_text.as_str().starts_with(raw_start) { - Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) - } else { - Name::new_text(raw_text.clone()) - } - } - - pub(crate) fn missing() -> Name { - Name::new_text("[missing name]".into()) - } - - pub(crate) fn as_tuple_index(&self) -> Option { - match self.0 { - Repr::TupleField(idx) => Some(idx), - _ => None, - } - } -} - -pub(crate) trait AsName { - fn as_name(&self) -> Name; -} - -impl AsName for ast::NameRef { - fn as_name(&self) -> Name { - match self.as_tuple_field() { - Some(idx) => Name::new_tuple_field(idx), - None => Name::resolve(self.text()), - } - } -} - -impl AsName for ast::Name { - fn as_name(&self) -> Name { - Name::resolve(self.text()) - } -} - -impl AsName for ast::FieldKind { - fn as_name(&self) -> Name { - match self { - ast::FieldKind::Name(nr) => nr.as_name(), - ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()), - } - } -} - -impl AsName for ra_db::Dependency { - fn as_name(&self) -> Name { - Name::new_text(self.name.clone()) - } -} - -// Primitives -pub(crate) const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); -pub(crate) const I8: Name = Name::new_inline_ascii(2, b"i8"); -pub(crate) const I16: Name = Name::new_inline_ascii(3, b"i16"); -pub(crate) const I32: Name = Name::new_inline_ascii(3, b"i32"); -pub(crate) const I64: Name = Name::new_inline_ascii(3, b"i64"); -pub(crate) const I128: Name = Name::new_inline_ascii(4, b"i128"); -pub(crate) const USIZE: Name = Name::new_inline_ascii(5, b"usize"); -pub(crate) const U8: Name = Name::new_inline_ascii(2, b"u8"); -pub(crate) const U16: Name = Name::new_inline_ascii(3, b"u16"); -pub(crate) const U32: Name = Name::new_inline_ascii(3, b"u32"); -pub(crate) const U64: Name = Name::new_inline_ascii(3, b"u64"); -pub(crate) const U128: Name = Name::new_inline_ascii(4, b"u128"); -pub(crate) const F32: Name = Name::new_inline_ascii(3, b"f32"); -pub(crate) const F64: Name = Name::new_inline_ascii(3, b"f64"); -pub(crate) const BOOL: Name = Name::new_inline_ascii(4, b"bool"); -pub(crate) const CHAR: Name = Name::new_inline_ascii(4, b"char"); -pub(crate) const STR: Name = Name::new_inline_ascii(3, b"str"); - -// Special names -pub(crate) const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); -pub(crate) const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); -pub(crate) const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); - -// Components of known path (value or mod name) -pub(crate) const STD: Name = Name::new_inline_ascii(3, b"std"); -pub(crate) const ITER: Name = Name::new_inline_ascii(4, b"iter"); -pub(crate) const OPS: Name = Name::new_inline_ascii(3, b"ops"); -pub(crate) const FUTURE: Name = Name::new_inline_ascii(6, b"future"); -pub(crate) const RESULT: Name = Name::new_inline_ascii(6, b"result"); -pub(crate) const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); - -// Components of known path (type name) -pub(crate) const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); -pub(crate) const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); -pub(crate) const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); -pub(crate) const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); -pub(crate) const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); -pub(crate) const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); -pub(crate) const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); -pub(crate) const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); -pub(crate) const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); +pub use hir_def::name::*; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index b325979f5b6d..39f585b446a9 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -48,7 +48,6 @@ //! on the result mod per_ns; -mod raw; mod collector; mod mod_resolution; #[cfg(test)] @@ -74,12 +73,9 @@ use crate::{ Trait, }; -pub(crate) use self::raw::{ImportSourceMap, RawItems}; +pub use self::per_ns::{Namespace, PerNs}; -pub use self::{ - per_ns::{Namespace, PerNs}, - raw::ImportId, -}; +pub use hir_def::nameres::raw::ImportId; /// Contains all top-level defs from a macro-expanded crate #[derive(Debug, PartialEq, Eq)] @@ -328,7 +324,8 @@ impl CrateDefMap { ) -> ResolvePathResult { let mut segments = path.segments.iter().enumerate(); let mut curr_per_ns: PerNs = match path.kind { - PathKind::DollarCrate(krate) => { + PathKind::DollarCrate(crate_id) => { + let krate = Crate { crate_id }; if krate == self.krate { tested_by!(macro_dollar_crate_self); PerNs::types(Module::new(self.krate, self.root).into()) diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index a94a0554c84c..2dd0a5877799 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,5 +1,6 @@ //! FIXME: write short doc here +use hir_def::nameres::raw; use ra_cfg::CfgOptions; use ra_db::FileId; use ra_syntax::{ast, SmolStr}; @@ -12,7 +13,7 @@ use crate::{ ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, name::MACRO_RULES, nameres::{ - diagnostics::DefDiagnostic, mod_resolution::ModDir, raw, Crate, CrateDefMap, CrateModuleId, + diagnostics::DefDiagnostic, mod_resolution::ModDir, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, }, Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs index f569aacdc6bd..abfe8b1c346e 100644 --- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn name_res_works_for_broken_modules() { - covers!(name_res_works_for_broken_modules); + // covers!(name_res_works_for_broken_modules); let map = def_map( " //- /lib.rs diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index bbe536bcb4a9..7f0ff4bfc773 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -1,422 +1 @@ -//! FIXME: write short doc here - -use std::{iter, sync::Arc}; - -use ra_syntax::{ - ast::{self, NameOwner, TypeAscriptionOwner}, - AstNode, -}; - -use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Path { - pub kind: PathKind, - pub segments: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct PathSegment { - pub name: Name, - pub args_and_bindings: Option>, -} - -/// Generic arguments to a path segment (e.g. the `i32` in `Option`). This -/// can (in the future) also include bindings of associated types, like in -/// `Iterator`. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericArgs { - pub args: Vec, - /// This specifies whether the args contain a Self type as the first - /// element. This is the case for path segments like ``, where - /// `T` is actually a type parameter for the path `Trait` specifying the - /// Self type. Otherwise, when we have a path `Trait`, the Self type - /// is left out. - pub has_self_type: bool, - /// Associated type bindings like in `Iterator`. - pub bindings: Vec<(Name, TypeRef)>, -} - -/// A single generic argument. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum GenericArg { - Type(TypeRef), - // or lifetime... -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum PathKind { - Plain, - Self_, - Super, - Crate, - // Absolute path - Abs, - // Type based path like `::foo` - Type(Box), - // `$crate` from macro expansion - DollarCrate(Crate), -} - -impl Path { - /// Calls `cb` with all paths, represented by this use item. - pub fn expand_use_item( - item_src: Source, - db: &impl AstDatabase, - mut cb: impl FnMut(Path, &ast::UseTree, bool, Option), - ) { - if let Some(tree) = item_src.ast.use_tree() { - expand_use_tree( - None, - tree, - &|| item_src.file_id.macro_crate(db).map(|crate_id| Crate { crate_id }), - &mut cb, - ); - } - } - - pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator) -> Path { - Path { - kind, - segments: segments - .into_iter() - .map(|name| PathSegment { name, args_and_bindings: None }) - .collect(), - } - } - - /// Converts an `ast::Path` to `Path`. Works with use trees. - /// DEPRECATED: It does not handle `$crate` from macro call. - pub fn from_ast(path: ast::Path) -> Option { - Path::parse(path, &|| None) - } - - /// Converts an `ast::Path` to `Path`. Works with use trees. - /// It correctly handles `$crate` based path from macro call. - pub fn from_src(source: Source, db: &impl AstDatabase) -> Option { - let file_id = source.file_id; - Path::parse(source.ast, &|| file_id.macro_crate(db).map(|crate_id| Crate { crate_id })) - } - - fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option) -> Option { - let mut kind = PathKind::Plain; - let mut segments = Vec::new(); - loop { - let segment = path.segment()?; - - if segment.has_colon_colon() { - kind = PathKind::Abs; - } - - match segment.kind()? { - ast::PathSegmentKind::Name(name) => { - if name.text() == "$crate" { - if let Some(macro_crate) = macro_crate() { - kind = PathKind::DollarCrate(macro_crate); - break; - } - } - - let args = segment - .type_arg_list() - .and_then(GenericArgs::from_ast) - .or_else(|| { - GenericArgs::from_fn_like_path_ast( - segment.param_list(), - segment.ret_type(), - ) - }) - .map(Arc::new); - let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; - segments.push(segment); - } - ast::PathSegmentKind::Type { type_ref, trait_ref } => { - assert!(path.qualifier().is_none()); // this can only occur at the first segment - - let self_type = TypeRef::from_ast(type_ref?); - - match trait_ref { - // ::foo - None => { - kind = PathKind::Type(Box::new(self_type)); - } - // >::Foo desugars to Trait::Foo - Some(trait_ref) => { - let path = Path::parse(trait_ref.path()?, macro_crate)?; - kind = path.kind; - let mut prefix_segments = path.segments; - prefix_segments.reverse(); - segments.extend(prefix_segments); - // Insert the type reference (T in the above example) as Self parameter for the trait - let mut last_segment = segments.last_mut()?; - if last_segment.args_and_bindings.is_none() { - last_segment.args_and_bindings = - Some(Arc::new(GenericArgs::empty())); - }; - let args = last_segment.args_and_bindings.as_mut().unwrap(); - let mut args_inner = Arc::make_mut(args); - args_inner.has_self_type = true; - args_inner.args.insert(0, GenericArg::Type(self_type)); - } - } - } - ast::PathSegmentKind::CrateKw => { - kind = PathKind::Crate; - break; - } - ast::PathSegmentKind::SelfKw => { - kind = PathKind::Self_; - break; - } - ast::PathSegmentKind::SuperKw => { - kind = PathKind::Super; - break; - } - } - path = match qualifier(&path) { - Some(it) => it, - None => break, - }; - } - segments.reverse(); - return Some(Path { kind, segments }); - - fn qualifier(path: &ast::Path) -> Option { - if let Some(q) = path.qualifier() { - return Some(q); - } - // FIXME: this bottom up traversal is not too precise. - // Should we handle do a top-down analysis, recording results? - let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; - let use_tree = use_tree_list.parent_use_tree(); - use_tree.path() - } - } - - /// Converts an `ast::NameRef` into a single-identifier `Path`. - pub fn from_name_ref(name_ref: &ast::NameRef) -> Path { - name_ref.as_name().into() - } - - /// `true` is this path is a single identifier, like `foo` - pub fn is_ident(&self) -> bool { - self.kind == PathKind::Plain && self.segments.len() == 1 - } - - /// `true` if this path is just a standalone `self` - pub fn is_self(&self) -> bool { - self.kind == PathKind::Self_ && self.segments.is_empty() - } - - /// If this path is a single identifier, like `foo`, return its name. - pub fn as_ident(&self) -> Option<&Name> { - if self.kind != PathKind::Plain || self.segments.len() > 1 { - return None; - } - self.segments.first().map(|s| &s.name) - } - - pub fn expand_macro_expr(&self) -> Option { - self.as_ident().and_then(|name| Some(name.clone())) - } - - pub fn is_type_relative(&self) -> bool { - match self.kind { - PathKind::Type(_) => true, - _ => false, - } - } -} - -impl GenericArgs { - pub(crate) fn from_ast(node: ast::TypeArgList) -> Option { - let mut args = Vec::new(); - for type_arg in node.type_args() { - let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); - args.push(GenericArg::Type(type_ref)); - } - // lifetimes ignored for now - let mut bindings = Vec::new(); - for assoc_type_arg in node.assoc_type_args() { - if let Some(name_ref) = assoc_type_arg.name_ref() { - let name = name_ref.as_name(); - let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); - bindings.push((name, type_ref)); - } - } - if args.is_empty() && bindings.is_empty() { - None - } else { - Some(GenericArgs { args, has_self_type: false, bindings }) - } - } - - /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) - /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). - pub(crate) fn from_fn_like_path_ast( - params: Option, - ret_type: Option, - ) -> Option { - let mut args = Vec::new(); - let mut bindings = Vec::new(); - if let Some(params) = params { - let mut param_types = Vec::new(); - for param in params.params() { - let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); - param_types.push(type_ref); - } - let arg = GenericArg::Type(TypeRef::Tuple(param_types)); - args.push(arg); - } - if let Some(ret_type) = ret_type { - let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); - bindings.push((name::OUTPUT_TYPE, type_ref)) - } - if args.is_empty() && bindings.is_empty() { - None - } else { - Some(GenericArgs { args, has_self_type: false, bindings }) - } - } - - pub(crate) fn empty() -> GenericArgs { - GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } - } -} - -impl From for Path { - fn from(name: Name) -> Path { - Path::from_simple_segments(PathKind::Plain, iter::once(name)) - } -} - -fn expand_use_tree( - prefix: Option, - tree: ast::UseTree, - macro_crate: &impl Fn() -> Option, - cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option), -) { - if let Some(use_tree_list) = tree.use_tree_list() { - let prefix = match tree.path() { - // E.g. use something::{{{inner}}}; - None => prefix, - // E.g. `use something::{inner}` (prefix is `None`, path is `something`) - // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) - Some(path) => match convert_path(prefix, path, macro_crate) { - Some(it) => Some(it), - None => return, // FIXME: report errors somewhere - }, - }; - for child_tree in use_tree_list.use_trees() { - expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); - } - } else { - let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); - if let Some(ast_path) = tree.path() { - // Handle self in a path. - // E.g. `use something::{self, <...>}` - if ast_path.qualifier().is_none() { - if let Some(segment) = ast_path.segment() { - if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { - if let Some(prefix) = prefix { - cb(prefix, &tree, false, alias); - return; - } - } - } - } - if let Some(path) = convert_path(prefix, ast_path, macro_crate) { - let is_glob = tree.has_star(); - cb(path, &tree, is_glob, alias) - } - // FIXME: report errors somewhere - // We get here if we do - } - } -} - -fn convert_path( - prefix: Option, - path: ast::Path, - macro_crate: &impl Fn() -> Option, -) -> Option { - let prefix = if let Some(qual) = path.qualifier() { - Some(convert_path(prefix, qual, macro_crate)?) - } else { - prefix - }; - - let segment = path.segment()?; - let res = match segment.kind()? { - ast::PathSegmentKind::Name(name) => { - if name.text() == "$crate" { - if let Some(krate) = macro_crate() { - return Some(Path::from_simple_segments( - PathKind::DollarCrate(krate), - iter::empty(), - )); - } - } - - // no type args in use - let mut res = prefix - .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); - res.segments.push(PathSegment { - name: name.as_name(), - args_and_bindings: None, // no type args in use - }); - res - } - ast::PathSegmentKind::CrateKw => { - if prefix.is_some() { - return None; - } - Path::from_simple_segments(PathKind::Crate, iter::empty()) - } - ast::PathSegmentKind::SelfKw => { - if prefix.is_some() { - return None; - } - Path::from_simple_segments(PathKind::Self_, iter::empty()) - } - ast::PathSegmentKind::SuperKw => { - if prefix.is_some() { - return None; - } - Path::from_simple_segments(PathKind::Super, iter::empty()) - } - ast::PathSegmentKind::Type { .. } => { - // not allowed in imports - return None; - } - }; - Some(res) -} - -pub mod known { - use super::{Path, PathKind}; - use crate::name; - - pub fn std_iter_into_iterator() -> Path { - Path::from_simple_segments( - PathKind::Abs, - vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], - ) - } - - pub fn std_ops_try() -> Path { - Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) - } - - pub fn std_result_result() -> Path { - Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) - } - - pub fn std_future_future() -> Path { - Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) - } - - pub fn std_boxed_box() -> Path { - Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) - } -} +pub use hir_def::path::*; diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs index 2cf06b250444..bd56ddbe61ae 100644 --- a/crates/ra_hir/src/type_ref.rs +++ b/crates/ra_hir/src/type_ref.rs @@ -1,162 +1 @@ -//! HIR for references to types. Paths in these are not yet resolved. They can -//! be directly created from an ast::TypeRef, without further queries. - -use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; - -use crate::Path; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Mutability { - Shared, - Mut, -} - -impl Mutability { - pub fn from_mutable(mutable: bool) -> Mutability { - if mutable { - Mutability::Mut - } else { - Mutability::Shared - } - } - - pub fn as_keyword_for_ref(self) -> &'static str { - match self { - Mutability::Shared => "", - Mutability::Mut => "mut ", - } - } - - pub fn as_keyword_for_ptr(self) -> &'static str { - match self { - Mutability::Shared => "const ", - Mutability::Mut => "mut ", - } - } -} - -/// Compare ty::Ty -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeRef { - Never, - Placeholder, - Tuple(Vec), - Path(Path), - RawPtr(Box, Mutability), - Reference(Box, Mutability), - Array(Box /*, Expr*/), - Slice(Box), - /// A fn pointer. Last element of the vector is the return type. - Fn(Vec), - // For - ImplTrait(Vec), - DynTrait(Vec), - Error, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeBound { - Path(Path), - // also for<> bounds - // also Lifetimes - Error, -} - -impl TypeRef { - /// Converts an `ast::TypeRef` to a `hir::TypeRef`. - pub(crate) fn from_ast(node: ast::TypeRef) -> Self { - match node { - ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()), - ast::TypeRef::TupleType(inner) => { - TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()) - } - ast::TypeRef::NeverType(..) => TypeRef::Never, - ast::TypeRef::PathType(inner) => { - // FIXME: Use `Path::from_src` - inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) - } - ast::TypeRef::PointerType(inner) => { - let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); - let mutability = Mutability::from_mutable(inner.is_mut()); - TypeRef::RawPtr(Box::new(inner_ty), mutability) - } - ast::TypeRef::ArrayType(inner) => { - TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) - } - ast::TypeRef::SliceType(inner) => { - TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) - } - ast::TypeRef::ReferenceType(inner) => { - let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); - let mutability = Mutability::from_mutable(inner.is_mut()); - TypeRef::Reference(Box::new(inner_ty), mutability) - } - ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, - ast::TypeRef::FnPointerType(inner) => { - let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref())); - let mut params = if let Some(pl) = inner.param_list() { - pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() - } else { - Vec::new() - }; - params.push(ret_ty); - TypeRef::Fn(params) - } - // for types are close enough for our purposes to the inner type for now... - ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), - ast::TypeRef::ImplTraitType(inner) => { - TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list())) - } - ast::TypeRef::DynTraitType(inner) => { - TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list())) - } - } - } - - pub(crate) fn from_ast_opt(node: Option) -> Self { - if let Some(node) = node { - TypeRef::from_ast(node) - } else { - TypeRef::Error - } - } - - pub fn unit() -> TypeRef { - TypeRef::Tuple(Vec::new()) - } -} - -pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option) -> Vec { - if let Some(type_bounds) = type_bounds_opt { - type_bounds.bounds().map(TypeBound::from_ast).collect() - } else { - vec![] - } -} - -impl TypeBound { - pub(crate) fn from_ast(node: ast::TypeBound) -> Self { - match node.kind() { - ast::TypeBoundKind::PathType(path_type) => { - let path = match path_type.path() { - Some(p) => p, - None => return TypeBound::Error, - }; - // FIXME: Use `Path::from_src` - let path = match Path::from_ast(path) { - Some(p) => p, - None => return TypeBound::Error, - }; - TypeBound::Path(path) - } - ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, - } - } - - pub fn as_path(&self) -> Option<&Path> { - match self { - TypeBound::Path(p) => Some(p), - _ => None, - } - } -} +pub use hir_def::type_ref::*; diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 75e93f2547bb..746c907e80da 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -6,9 +6,16 @@ authors = ["rust-analyzer developers"] [dependencies] log = "0.4.5" +once_cell = "1.0.1" +relative-path = "1.0.0" +rustc-hash = "1.0" ra_arena = { path = "../ra_arena" } ra_db = { path = "../ra_db" } ra_syntax = { path = "../ra_syntax" } ra_prof = { path = "../ra_prof" } hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } +test_utils = { path = "../test_utils" } +mbe = { path = "../ra_mbe", package = "ra_mbe" } +ra_cfg = { path = "../ra_cfg" } +tt = { path = "../ra_tt", package = "ra_tt" } diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs new file mode 100644 index 000000000000..248f03cdfdd4 --- /dev/null +++ b/crates/ra_hir_def/src/attr.rs @@ -0,0 +1,91 @@ +//! A higher level attributes based on TokenTree, with also some shortcuts. + +use std::sync::Arc; + +use hir_expand::db::AstDatabase; +use mbe::ast_to_token_tree; +use ra_cfg::CfgOptions; +use ra_syntax::{ + ast::{self, AstNode, AttrsOwner}, + SmolStr, +}; +use tt::Subtree; + +use crate::{path::Path, HirFileId, Source}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Attr { + pub(crate) path: Path, + pub(crate) input: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum AttrInput { + Literal(SmolStr), + TokenTree(Subtree), +} + +impl Attr { + pub(crate) fn from_src( + Source { file_id, ast }: Source, + db: &impl AstDatabase, + ) -> Option { + let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?; + let input = match ast.input() { + None => None, + Some(ast::AttrInput::Literal(lit)) => { + // FIXME: escape? raw string? + let value = lit.syntax().first_token()?.text().trim_matches('"').into(); + Some(AttrInput::Literal(value)) + } + Some(ast::AttrInput::TokenTree(tt)) => { + Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) + } + }; + + Some(Attr { path, input }) + } + + pub fn from_attrs_owner( + file_id: HirFileId, + owner: &dyn AttrsOwner, + db: &impl AstDatabase, + ) -> Option> { + let mut attrs = owner.attrs().peekable(); + if attrs.peek().is_none() { + // Avoid heap allocation + return None; + } + Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) + } + + pub fn is_simple_atom(&self, name: &str) -> bool { + // FIXME: Avoid cloning + self.path.as_ident().map_or(false, |s| s.to_string() == name) + } + + // FIXME: handle cfg_attr :-) + pub fn as_cfg(&self) -> Option<&Subtree> { + if !self.is_simple_atom("cfg") { + return None; + } + match &self.input { + Some(AttrInput::TokenTree(subtree)) => Some(subtree), + _ => None, + } + } + + pub fn as_path(&self) -> Option<&SmolStr> { + if !self.is_simple_atom("path") { + return None; + } + match &self.input { + Some(AttrInput::Literal(it)) => Some(it), + _ => None, + } + } + + pub fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option { + cfg_options.is_cfg_enabled(self.as_cfg()?) + } +} diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index f6f976c860a0..b271636b07e7 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -1,8 +1,12 @@ //! Defines database & queries for name resolution. +use std::sync::Arc; +use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::{salsa, SourceDatabase}; use ra_syntax::ast; +use crate::nameres::raw::{ImportSourceMap, RawItems}; + #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { #[salsa::interned] @@ -10,6 +14,8 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_struct(&self, loc: crate::ItemLoc) -> crate::StructId; #[salsa::interned] + fn intern_union(&self, loc: crate::ItemLoc) -> crate::UnionId; + #[salsa::interned] fn intern_enum(&self, loc: crate::ItemLoc) -> crate::EnumId; #[salsa::interned] fn intern_const(&self, loc: crate::ItemLoc) -> crate::ConstId; @@ -20,3 +26,15 @@ pub trait InternDatabase: SourceDatabase { #[salsa::interned] fn intern_type_alias(&self, loc: crate::ItemLoc) -> crate::TypeAliasId; } + +#[salsa::query_group(DefDatabase2Storage)] +pub trait DefDatabase2: InternDatabase + AstDatabase { + #[salsa::invoke(RawItems::raw_items_with_source_map_query)] + fn raw_items_with_source_map( + &self, + file_id: HirFileId, + ) -> (Arc, Arc); + + #[salsa::invoke(RawItems::raw_items_query)] + fn raw_items(&self, file_id: HirFileId) -> Arc; +} diff --git a/crates/ra_hir_def/src/either.rs b/crates/ra_hir_def/src/either.rs new file mode 100644 index 000000000000..83583ef8bd3c --- /dev/null +++ b/crates/ra_hir_def/src/either.rs @@ -0,0 +1,54 @@ +//! FIXME: write short doc here + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Either { + A(A), + B(B), +} + +impl Either { + pub fn either(self, f1: F1, f2: F2) -> R + where + F1: FnOnce(A) -> R, + F2: FnOnce(B) -> R, + { + match self { + Either::A(a) => f1(a), + Either::B(b) => f2(b), + } + } + pub fn map(self, f1: F1, f2: F2) -> Either + where + F1: FnOnce(A) -> U, + F2: FnOnce(B) -> V, + { + match self { + Either::A(a) => Either::A(f1(a)), + Either::B(b) => Either::B(f2(b)), + } + } + pub fn map_a(self, f: F) -> Either + where + F: FnOnce(A) -> U, + { + self.map(f, |it| it) + } + pub fn a(self) -> Option { + match self { + Either::A(it) => Some(it), + Either::B(_) => None, + } + } + pub fn b(self) -> Option { + match self { + Either::A(_) => None, + Either::B(it) => Some(it), + } + } + pub fn as_ref(&self) -> Either<&A, &B> { + match self { + Either::A(it) => Either::A(it), + Either::B(it) => Either::B(it), + } + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 4d6b9db033f9..95d50332568a 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -8,12 +8,20 @@ //! actually true. pub mod db; +pub mod either; +pub mod attr; +pub mod name; +pub mod path; +pub mod type_ref; + +// FIXME: this should be private +pub mod nameres; use std::hash::{Hash, Hasher}; use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; use ra_arena::{impl_arena_id, RawId}; -use ra_db::{salsa, CrateId}; +use ra_db::{salsa, CrateId, FileId}; use ra_syntax::{ast, AstNode, SyntaxNode}; use crate::db::InternDatabase; @@ -24,6 +32,68 @@ pub struct Source { pub ast: T, } +pub enum ModuleSource { + SourceFile(ast::SourceFile), + Module(ast::Module), +} + +impl ModuleSource { + pub fn new( + db: &impl db::DefDatabase2, + file_id: Option, + decl_id: Option>, + ) -> ModuleSource { + match (file_id, decl_id) { + (Some(file_id), _) => { + let source_file = db.parse(file_id).tree(); + ModuleSource::SourceFile(source_file) + } + (None, Some(item_id)) => { + let module = item_id.to_node(db); + assert!(module.item_list().is_some(), "expected inline module"); + ModuleSource::Module(module) + } + (None, None) => panic!(), + } + } + + // FIXME: this methods do not belong here + pub fn from_position( + db: &impl db::DefDatabase2, + position: ra_db::FilePosition, + ) -> ModuleSource { + let parse = db.parse(position.file_id); + match &ra_syntax::algo::find_node_at_offset::( + parse.tree().syntax(), + position.offset, + ) { + Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()), + _ => { + let source_file = parse.tree(); + ModuleSource::SourceFile(source_file) + } + } + } + + pub fn from_child_node( + db: &impl db::DefDatabase2, + file_id: FileId, + child: &SyntaxNode, + ) -> ModuleSource { + if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) { + ModuleSource::Module(m) + } else { + let source_file = db.parse(file_id).tree(); + ModuleSource::SourceFile(source_file) + } + } + + pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource { + let source_file = db.parse(file_id).tree(); + ModuleSource::SourceFile(source_file) + } +} + impl Source { pub fn map U, U>(self, f: F) -> Source { Source { file_id: self.file_id, ast: f(self.ast) } @@ -155,6 +225,18 @@ impl AstItemDef for StructId { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct UnionId(salsa::InternId); +impl_intern_key!(UnionId); +impl AstItemDef for UnionId { + fn intern(db: &impl InternDatabase, loc: ItemLoc) -> Self { + db.intern_union(loc) + } + fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc { + db.lookup_intern_union(self) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumId(salsa::InternId); impl_intern_key!(EnumId); @@ -167,6 +249,17 @@ impl AstItemDef for EnumId { } } +// FIXME: rename to `VariantId`, only enums can ave variants +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumVariantId { + parent: EnumId, + local_id: LocalEnumVariantId, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct LocalEnumVariantId(RawId); +impl_arena_id!(LocalEnumVariantId); + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstId(salsa::InternId); impl_intern_key!(ConstId); diff --git a/crates/ra_hir_def/src/name.rs b/crates/ra_hir_def/src/name.rs new file mode 100644 index 000000000000..720896ee8ebf --- /dev/null +++ b/crates/ra_hir_def/src/name.rs @@ -0,0 +1,142 @@ +//! FIXME: write short doc here + +use std::fmt; + +use ra_syntax::{ast, SmolStr}; + +/// `Name` is a wrapper around string, which is used in hir for both references +/// and declarations. In theory, names should also carry hygiene info, but we are +/// not there yet! +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Name(Repr); + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum Repr { + Text(SmolStr), + TupleField(usize), +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.0 { + Repr::Text(text) => fmt::Display::fmt(&text, f), + Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), + } + } +} + +impl Name { + /// Note: this is private to make creating name from random string hard. + /// Hopefully, this should allow us to integrate hygiene cleaner in the + /// future, and to switch to interned representation of names. + const fn new_text(text: SmolStr) -> Name { + Name(Repr::Text(text)) + } + + pub fn new_tuple_field(idx: usize) -> Name { + Name(Repr::TupleField(idx)) + } + + /// Shortcut to create inline plain text name + const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { + Name::new_text(SmolStr::new_inline_from_ascii(len, text)) + } + + /// Resolve a name from the text of token. + fn resolve(raw_text: &SmolStr) -> Name { + let raw_start = "r#"; + if raw_text.as_str().starts_with(raw_start) { + Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) + } else { + Name::new_text(raw_text.clone()) + } + } + + pub fn missing() -> Name { + Name::new_text("[missing name]".into()) + } + + pub fn as_tuple_index(&self) -> Option { + match self.0 { + Repr::TupleField(idx) => Some(idx), + _ => None, + } + } +} + +pub trait AsName { + fn as_name(&self) -> Name; +} + +impl AsName for ast::NameRef { + fn as_name(&self) -> Name { + match self.as_tuple_field() { + Some(idx) => Name::new_tuple_field(idx), + None => Name::resolve(self.text()), + } + } +} + +impl AsName for ast::Name { + fn as_name(&self) -> Name { + Name::resolve(self.text()) + } +} + +impl AsName for ast::FieldKind { + fn as_name(&self) -> Name { + match self { + ast::FieldKind::Name(nr) => nr.as_name(), + ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()), + } + } +} + +impl AsName for ra_db::Dependency { + fn as_name(&self) -> Name { + Name::new_text(self.name.clone()) + } +} + +// Primitives +pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); +pub const I8: Name = Name::new_inline_ascii(2, b"i8"); +pub const I16: Name = Name::new_inline_ascii(3, b"i16"); +pub const I32: Name = Name::new_inline_ascii(3, b"i32"); +pub const I64: Name = Name::new_inline_ascii(3, b"i64"); +pub const I128: Name = Name::new_inline_ascii(4, b"i128"); +pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); +pub const U8: Name = Name::new_inline_ascii(2, b"u8"); +pub const U16: Name = Name::new_inline_ascii(3, b"u16"); +pub const U32: Name = Name::new_inline_ascii(3, b"u32"); +pub const U64: Name = Name::new_inline_ascii(3, b"u64"); +pub const U128: Name = Name::new_inline_ascii(4, b"u128"); +pub const F32: Name = Name::new_inline_ascii(3, b"f32"); +pub const F64: Name = Name::new_inline_ascii(3, b"f64"); +pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); +pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); +pub const STR: Name = Name::new_inline_ascii(3, b"str"); + +// Special names +pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); +pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); +pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); + +// Components of known path (value or mod name) +pub const STD: Name = Name::new_inline_ascii(3, b"std"); +pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); +pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); +pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); +pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); +pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); + +// Components of known path (type name) +pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); +pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); +pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); +pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); +pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); +pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); +pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); +pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); +pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs new file mode 100644 index 000000000000..1a3f7667d2a2 --- /dev/null +++ b/crates/ra_hir_def/src/nameres.rs @@ -0,0 +1 @@ +pub mod raw; diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs similarity index 91% rename from crates/ra_hir/src/nameres/raw.rs rename to crates/ra_hir_def/src/nameres/raw.rs index 57f2929c38ed..13b9fbf48f61 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -2,6 +2,7 @@ use std::{ops::Index, sync::Arc}; +use hir_expand::{ast_id_map::AstIdMap, db::AstDatabase}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, @@ -11,8 +12,11 @@ use test_utils::tested_by; use crate::{ attr::Attr, - db::{AstDatabase, DefDatabase}, - AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, + db::DefDatabase2, + either::Either, + name::{AsName, Name}, + path::Path, + FileAstId, HirFileId, ModuleSource, Source, }; /// `RawItems` is a set of top-level items in a file (except for impls). @@ -48,7 +52,7 @@ impl ImportSourceMap { self.map.insert(import, ptr) } - pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource { + pub fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource { let file = match source { ModuleSource::SourceFile(file) => file.clone(), ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), @@ -60,14 +64,14 @@ impl ImportSourceMap { impl RawItems { pub(crate) fn raw_items_query( - db: &(impl DefDatabase + AstDatabase), + db: &(impl DefDatabase2 + AstDatabase), file_id: HirFileId, ) -> Arc { db.raw_items_with_source_map(file_id).0 } pub(crate) fn raw_items_with_source_map_query( - db: &(impl DefDatabase + AstDatabase), + db: &(impl DefDatabase2 + AstDatabase), file_id: HirFileId, ) -> (Arc, Arc) { let mut collector = RawItemsCollector { @@ -87,7 +91,7 @@ impl RawItems { (Arc::new(collector.raw_items), Arc::new(collector.source_map)) } - pub(super) fn items(&self) -> &[RawItem] { + pub fn items(&self) -> &[RawItem] { &self.items } } @@ -124,19 +128,19 @@ impl Index for RawItems { type Attrs = Option>; #[derive(Debug, PartialEq, Eq, Clone)] -pub(super) struct RawItem { +pub struct RawItem { attrs: Attrs, - pub(super) kind: RawItemKind, + pub kind: RawItemKind, } impl RawItem { - pub(super) fn attrs(&self) -> &[Attr] { + pub fn attrs(&self) -> &[Attr] { self.attrs.as_ref().map_or(&[], |it| &*it) } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(super) enum RawItemKind { +pub enum RawItemKind { Module(Module), Import(ImportId), Def(Def), @@ -144,11 +148,11 @@ pub(super) enum RawItemKind { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(super) struct Module(RawId); +pub struct Module(RawId); impl_arena_id!(Module); #[derive(Debug, PartialEq, Eq)] -pub(super) enum ModuleData { +pub enum ModuleData { Declaration { name: Name, ast_id: FileAstId }, Definition { name: Name, ast_id: FileAstId, items: Vec }, } @@ -159,26 +163,26 @@ impl_arena_id!(ImportId); #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportData { - pub(super) path: Path, - pub(super) alias: Option, - pub(super) is_glob: bool, - pub(super) is_prelude: bool, - pub(super) is_extern_crate: bool, - pub(super) is_macro_use: bool, + pub path: Path, + pub alias: Option, + pub is_glob: bool, + pub is_prelude: bool, + pub is_extern_crate: bool, + pub is_macro_use: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(super) struct Def(RawId); +pub struct Def(RawId); impl_arena_id!(Def); #[derive(Debug, PartialEq, Eq)] -pub(super) struct DefData { - pub(super) name: Name, - pub(super) kind: DefKind, +pub struct DefData { + pub name: Name, + pub kind: DefKind, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub(super) enum DefKind { +pub enum DefKind { Function(FileAstId), Struct(FileAstId), Union(FileAstId), @@ -190,15 +194,15 @@ pub(super) enum DefKind { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(super) struct Macro(RawId); +pub struct Macro(RawId); impl_arena_id!(Macro); #[derive(Debug, PartialEq, Eq)] -pub(super) struct MacroData { - pub(super) ast_id: FileAstId, - pub(super) path: Path, - pub(super) name: Option, - pub(super) export: bool, +pub struct MacroData { + pub ast_id: FileAstId, + pub path: Path, + pub name: Option, + pub export: bool, } struct RawItemsCollector { diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs new file mode 100644 index 000000000000..fe060437df8f --- /dev/null +++ b/crates/ra_hir_def/src/path.rs @@ -0,0 +1,423 @@ +//! FIXME: write short doc here + +use std::{iter, sync::Arc}; + +use hir_expand::db::AstDatabase; +use ra_db::CrateId; +use ra_syntax::{ + ast::{self, NameOwner, TypeAscriptionOwner}, + AstNode, +}; + +use crate::{ + name::{self, AsName, Name}, + type_ref::TypeRef, + Source, +}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Path { + pub kind: PathKind, + pub segments: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PathSegment { + pub name: Name, + pub args_and_bindings: Option>, +} + +/// Generic arguments to a path segment (e.g. the `i32` in `Option`). This +/// can (in the future) also include bindings of associated types, like in +/// `Iterator`. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericArgs { + pub args: Vec, + /// This specifies whether the args contain a Self type as the first + /// element. This is the case for path segments like ``, where + /// `T` is actually a type parameter for the path `Trait` specifying the + /// Self type. Otherwise, when we have a path `Trait`, the Self type + /// is left out. + pub has_self_type: bool, + /// Associated type bindings like in `Iterator`. + pub bindings: Vec<(Name, TypeRef)>, +} + +/// A single generic argument. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum GenericArg { + Type(TypeRef), + // or lifetime... +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum PathKind { + Plain, + Self_, + Super, + Crate, + // Absolute path + Abs, + // Type based path like `::foo` + Type(Box), + // `$crate` from macro expansion + DollarCrate(CrateId), +} + +impl Path { + /// Calls `cb` with all paths, represented by this use item. + pub fn expand_use_item( + item_src: Source, + db: &impl AstDatabase, + mut cb: impl FnMut(Path, &ast::UseTree, bool, Option), + ) { + if let Some(tree) = item_src.ast.use_tree() { + expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); + } + } + + pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator) -> Path { + Path { + kind, + segments: segments + .into_iter() + .map(|name| PathSegment { name, args_and_bindings: None }) + .collect(), + } + } + + /// Converts an `ast::Path` to `Path`. Works with use trees. + /// DEPRECATED: It does not handle `$crate` from macro call. + pub fn from_ast(path: ast::Path) -> Option { + Path::parse(path, &|| None) + } + + /// Converts an `ast::Path` to `Path`. Works with use trees. + /// It correctly handles `$crate` based path from macro call. + pub fn from_src(source: Source, db: &impl AstDatabase) -> Option { + let file_id = source.file_id; + Path::parse(source.ast, &|| file_id.macro_crate(db)) + } + + fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option) -> Option { + let mut kind = PathKind::Plain; + let mut segments = Vec::new(); + loop { + let segment = path.segment()?; + + if segment.has_colon_colon() { + kind = PathKind::Abs; + } + + match segment.kind()? { + ast::PathSegmentKind::Name(name) => { + if name.text() == "$crate" { + if let Some(macro_crate) = macro_crate() { + kind = PathKind::DollarCrate(macro_crate); + break; + } + } + + let args = segment + .type_arg_list() + .and_then(GenericArgs::from_ast) + .or_else(|| { + GenericArgs::from_fn_like_path_ast( + segment.param_list(), + segment.ret_type(), + ) + }) + .map(Arc::new); + let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; + segments.push(segment); + } + ast::PathSegmentKind::Type { type_ref, trait_ref } => { + assert!(path.qualifier().is_none()); // this can only occur at the first segment + + let self_type = TypeRef::from_ast(type_ref?); + + match trait_ref { + // ::foo + None => { + kind = PathKind::Type(Box::new(self_type)); + } + // >::Foo desugars to Trait::Foo + Some(trait_ref) => { + let path = Path::parse(trait_ref.path()?, macro_crate)?; + kind = path.kind; + let mut prefix_segments = path.segments; + prefix_segments.reverse(); + segments.extend(prefix_segments); + // Insert the type reference (T in the above example) as Self parameter for the trait + let mut last_segment = segments.last_mut()?; + if last_segment.args_and_bindings.is_none() { + last_segment.args_and_bindings = + Some(Arc::new(GenericArgs::empty())); + }; + let args = last_segment.args_and_bindings.as_mut().unwrap(); + let mut args_inner = Arc::make_mut(args); + args_inner.has_self_type = true; + args_inner.args.insert(0, GenericArg::Type(self_type)); + } + } + } + ast::PathSegmentKind::CrateKw => { + kind = PathKind::Crate; + break; + } + ast::PathSegmentKind::SelfKw => { + kind = PathKind::Self_; + break; + } + ast::PathSegmentKind::SuperKw => { + kind = PathKind::Super; + break; + } + } + path = match qualifier(&path) { + Some(it) => it, + None => break, + }; + } + segments.reverse(); + return Some(Path { kind, segments }); + + fn qualifier(path: &ast::Path) -> Option { + if let Some(q) = path.qualifier() { + return Some(q); + } + // FIXME: this bottom up traversal is not too precise. + // Should we handle do a top-down analysis, recording results? + let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; + let use_tree = use_tree_list.parent_use_tree(); + use_tree.path() + } + } + + /// Converts an `ast::NameRef` into a single-identifier `Path`. + pub fn from_name_ref(name_ref: &ast::NameRef) -> Path { + name_ref.as_name().into() + } + + /// `true` is this path is a single identifier, like `foo` + pub fn is_ident(&self) -> bool { + self.kind == PathKind::Plain && self.segments.len() == 1 + } + + /// `true` if this path is just a standalone `self` + pub fn is_self(&self) -> bool { + self.kind == PathKind::Self_ && self.segments.is_empty() + } + + /// If this path is a single identifier, like `foo`, return its name. + pub fn as_ident(&self) -> Option<&Name> { + if self.kind != PathKind::Plain || self.segments.len() > 1 { + return None; + } + self.segments.first().map(|s| &s.name) + } + + pub fn expand_macro_expr(&self) -> Option { + self.as_ident().and_then(|name| Some(name.clone())) + } + + pub fn is_type_relative(&self) -> bool { + match self.kind { + PathKind::Type(_) => true, + _ => false, + } + } +} + +impl GenericArgs { + pub fn from_ast(node: ast::TypeArgList) -> Option { + let mut args = Vec::new(); + for type_arg in node.type_args() { + let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); + args.push(GenericArg::Type(type_ref)); + } + // lifetimes ignored for now + let mut bindings = Vec::new(); + for assoc_type_arg in node.assoc_type_args() { + if let Some(name_ref) = assoc_type_arg.name_ref() { + let name = name_ref.as_name(); + let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); + bindings.push((name, type_ref)); + } + } + if args.is_empty() && bindings.is_empty() { + None + } else { + Some(GenericArgs { args, has_self_type: false, bindings }) + } + } + + /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) + /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). + pub(crate) fn from_fn_like_path_ast( + params: Option, + ret_type: Option, + ) -> Option { + let mut args = Vec::new(); + let mut bindings = Vec::new(); + if let Some(params) = params { + let mut param_types = Vec::new(); + for param in params.params() { + let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); + param_types.push(type_ref); + } + let arg = GenericArg::Type(TypeRef::Tuple(param_types)); + args.push(arg); + } + if let Some(ret_type) = ret_type { + let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); + bindings.push((name::OUTPUT_TYPE, type_ref)) + } + if args.is_empty() && bindings.is_empty() { + None + } else { + Some(GenericArgs { args, has_self_type: false, bindings }) + } + } + + pub(crate) fn empty() -> GenericArgs { + GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } + } +} + +impl From for Path { + fn from(name: Name) -> Path { + Path::from_simple_segments(PathKind::Plain, iter::once(name)) + } +} + +fn expand_use_tree( + prefix: Option, + tree: ast::UseTree, + macro_crate: &impl Fn() -> Option, + cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option), +) { + if let Some(use_tree_list) = tree.use_tree_list() { + let prefix = match tree.path() { + // E.g. use something::{{{inner}}}; + None => prefix, + // E.g. `use something::{inner}` (prefix is `None`, path is `something`) + // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) + Some(path) => match convert_path(prefix, path, macro_crate) { + Some(it) => Some(it), + None => return, // FIXME: report errors somewhere + }, + }; + for child_tree in use_tree_list.use_trees() { + expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); + } + } else { + let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); + if let Some(ast_path) = tree.path() { + // Handle self in a path. + // E.g. `use something::{self, <...>}` + if ast_path.qualifier().is_none() { + if let Some(segment) = ast_path.segment() { + if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { + if let Some(prefix) = prefix { + cb(prefix, &tree, false, alias); + return; + } + } + } + } + if let Some(path) = convert_path(prefix, ast_path, macro_crate) { + let is_glob = tree.has_star(); + cb(path, &tree, is_glob, alias) + } + // FIXME: report errors somewhere + // We get here if we do + } + } +} + +fn convert_path( + prefix: Option, + path: ast::Path, + macro_crate: &impl Fn() -> Option, +) -> Option { + let prefix = if let Some(qual) = path.qualifier() { + Some(convert_path(prefix, qual, macro_crate)?) + } else { + prefix + }; + + let segment = path.segment()?; + let res = match segment.kind()? { + ast::PathSegmentKind::Name(name) => { + if name.text() == "$crate" { + if let Some(krate) = macro_crate() { + return Some(Path::from_simple_segments( + PathKind::DollarCrate(krate), + iter::empty(), + )); + } + } + + // no type args in use + let mut res = prefix + .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); + res.segments.push(PathSegment { + name: name.as_name(), + args_and_bindings: None, // no type args in use + }); + res + } + ast::PathSegmentKind::CrateKw => { + if prefix.is_some() { + return None; + } + Path::from_simple_segments(PathKind::Crate, iter::empty()) + } + ast::PathSegmentKind::SelfKw => { + if prefix.is_some() { + return None; + } + Path::from_simple_segments(PathKind::Self_, iter::empty()) + } + ast::PathSegmentKind::SuperKw => { + if prefix.is_some() { + return None; + } + Path::from_simple_segments(PathKind::Super, iter::empty()) + } + ast::PathSegmentKind::Type { .. } => { + // not allowed in imports + return None; + } + }; + Some(res) +} + +pub mod known { + use super::{Path, PathKind}; + use crate::name; + + pub fn std_iter_into_iterator() -> Path { + Path::from_simple_segments( + PathKind::Abs, + vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], + ) + } + + pub fn std_ops_try() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) + } + + pub fn std_result_result() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) + } + + pub fn std_future_future() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) + } + + pub fn std_boxed_box() -> Path { + Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) + } +} diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs new file mode 100644 index 000000000000..8af061116de8 --- /dev/null +++ b/crates/ra_hir_def/src/type_ref.rs @@ -0,0 +1,162 @@ +//! HIR for references to types. Paths in these are not yet resolved. They can +//! be directly created from an ast::TypeRef, without further queries. + +use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; + +use crate::path::Path; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Mutability { + Shared, + Mut, +} + +impl Mutability { + pub fn from_mutable(mutable: bool) -> Mutability { + if mutable { + Mutability::Mut + } else { + Mutability::Shared + } + } + + pub fn as_keyword_for_ref(self) -> &'static str { + match self { + Mutability::Shared => "", + Mutability::Mut => "mut ", + } + } + + pub fn as_keyword_for_ptr(self) -> &'static str { + match self { + Mutability::Shared => "const ", + Mutability::Mut => "mut ", + } + } +} + +/// Compare ty::Ty +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum TypeRef { + Never, + Placeholder, + Tuple(Vec), + Path(Path), + RawPtr(Box, Mutability), + Reference(Box, Mutability), + Array(Box /*, Expr*/), + Slice(Box), + /// A fn pointer. Last element of the vector is the return type. + Fn(Vec), + // For + ImplTrait(Vec), + DynTrait(Vec), + Error, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum TypeBound { + Path(Path), + // also for<> bounds + // also Lifetimes + Error, +} + +impl TypeRef { + /// Converts an `ast::TypeRef` to a `hir::TypeRef`. + pub fn from_ast(node: ast::TypeRef) -> Self { + match node { + ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()), + ast::TypeRef::TupleType(inner) => { + TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()) + } + ast::TypeRef::NeverType(..) => TypeRef::Never, + ast::TypeRef::PathType(inner) => { + // FIXME: Use `Path::from_src` + inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) + } + ast::TypeRef::PointerType(inner) => { + let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); + let mutability = Mutability::from_mutable(inner.is_mut()); + TypeRef::RawPtr(Box::new(inner_ty), mutability) + } + ast::TypeRef::ArrayType(inner) => { + TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) + } + ast::TypeRef::SliceType(inner) => { + TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) + } + ast::TypeRef::ReferenceType(inner) => { + let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); + let mutability = Mutability::from_mutable(inner.is_mut()); + TypeRef::Reference(Box::new(inner_ty), mutability) + } + ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, + ast::TypeRef::FnPointerType(inner) => { + let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref())); + let mut params = if let Some(pl) = inner.param_list() { + pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() + } else { + Vec::new() + }; + params.push(ret_ty); + TypeRef::Fn(params) + } + // for types are close enough for our purposes to the inner type for now... + ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), + ast::TypeRef::ImplTraitType(inner) => { + TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list())) + } + ast::TypeRef::DynTraitType(inner) => { + TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list())) + } + } + } + + pub fn from_ast_opt(node: Option) -> Self { + if let Some(node) = node { + TypeRef::from_ast(node) + } else { + TypeRef::Error + } + } + + pub fn unit() -> TypeRef { + TypeRef::Tuple(Vec::new()) + } +} + +pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option) -> Vec { + if let Some(type_bounds) = type_bounds_opt { + type_bounds.bounds().map(TypeBound::from_ast).collect() + } else { + vec![] + } +} + +impl TypeBound { + pub fn from_ast(node: ast::TypeBound) -> Self { + match node.kind() { + ast::TypeBoundKind::PathType(path_type) => { + let path = match path_type.path() { + Some(p) => p, + None => return TypeBound::Error, + }; + // FIXME: Use `Path::from_src` + let path = match Path::from_ast(path) { + Some(p) => p, + None => return TypeBound::Error, + }; + TypeBound::Path(path) + } + ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error, + } + } + + pub fn as_path(&self) -> Option<&Path> { + match self { + TypeBound::Path(p) => Some(p), + _ => None, + } + } +} diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 6b35386730c9..3c0ef8f1c05a 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -12,7 +12,7 @@ use std::hash::{Hash, Hasher}; use ra_db::{salsa, CrateId, FileId}; use ra_syntax::ast::{self, AstNode}; -use crate::{ast_id_map::FileAstId, db::AstDatabase}; +use crate::ast_id_map::FileAstId; /// Input to the analyzer is a set of files, where each file is identified by /// `FileId` and contains source code. However, another source of source code in @@ -50,7 +50,7 @@ impl From for HirFileId { impl HirFileId { /// For macro-expansion files, returns the file original source file the /// expansion originated from. - pub fn original_file(self, db: &dyn AstDatabase) -> FileId { + pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId { match self.0 { HirFileIdRepr::FileId(file_id) => file_id, HirFileIdRepr::MacroFile(macro_file) => { @@ -61,7 +61,7 @@ impl HirFileId { } /// Get the crate which the macro lives in, if it is a macro file. - pub fn macro_crate(self, db: &dyn AstDatabase) -> Option { + pub fn macro_crate(self, db: &dyn db::AstDatabase) -> Option { match self.0 { HirFileIdRepr::FileId(_) => None, HirFileIdRepr::MacroFile(macro_file) => { @@ -154,7 +154,7 @@ impl AstId { self.file_id } - pub fn to_node(&self, db: &dyn AstDatabase) -> N { + pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { let root = db.parse_or_expand(self.file_id).unwrap(); db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) } From f8ddef875af08f6c67fe69f7803f3926bc6f66bb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 17:19:30 +0300 Subject: [PATCH 081/102] remove forward pointer for name --- crates/ra_hir/src/adt.rs | 3 ++- crates/ra_hir/src/code_model.rs | 18 +++++++++--------- crates/ra_hir/src/expr/lower.rs | 4 ++-- crates/ra_hir/src/from_source.rs | 2 +- crates/ra_hir/src/generics.rs | 14 +++++++++----- crates/ra_hir/src/lib.rs | 6 +++--- crates/ra_hir/src/name.rs | 1 - crates/ra_hir/src/nameres/collector.rs | 5 ++--- crates/ra_hir/src/resolve.rs | 20 +++++++++++--------- crates/ra_hir/src/source_binder.rs | 5 +++-- crates/ra_hir/src/traits.rs | 4 ++-- crates/ra_hir/src/ty/autoderef.rs | 3 ++- crates/ra_hir/src/ty/infer.rs | 2 +- crates/ra_hir/src/ty/infer/expr.rs | 3 ++- crates/ra_hir/src/ty/traits/chalk.rs | 3 ++- crates/ra_hir/src/type_alias.rs | 2 +- 16 files changed, 52 insertions(+), 43 deletions(-) delete mode 100644 crates/ra_hir/src/name.rs diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 3e9cd3c63d46..ce64980bbceb 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,13 +3,14 @@ use std::sync::Arc; +use hir_def::name::AsName; use ra_arena::{impl_arena_id, Arena, RawId}; use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, type_ref::TypeRef, - AsName, Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField, + Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField, }; impl Struct { diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index de1377aa45ab..7848d0a3f628 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -5,7 +5,13 @@ pub(crate) mod docs; use std::sync::Arc; -use hir_def::{CrateModuleId, ModuleId}; +use hir_def::{ + name::{ + self, AsName, BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, + U16, U32, U64, U8, USIZE, + }, + CrateModuleId, ModuleId, +}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; @@ -20,10 +26,6 @@ use crate::{ TypeAliasId, }, impl_block::ImplBlock, - name::{ - BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, U32, U64, - U8, USIZE, - }, nameres::{ImportId, ModuleScope, Namespace}, resolve::{Resolver, Scope, TypeNs}, traits::TraitData, @@ -33,7 +35,7 @@ use crate::{ }, type_ref::Mutability, type_ref::TypeRef, - AsName, Either, HasSource, Name, Ty, + Either, HasSource, Name, Ty, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -898,9 +900,7 @@ impl Trait { .where_predicates .iter() .filter_map(|pred| match &pred.type_ref { - TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => { - pred.bound.as_path() - } + TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), _ => None, }) .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index b3a9a2e6b9a6..cf8a41b1e862 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,5 +1,6 @@ //! FIXME: write short doc here +use hir_def::name::{self, AsName, Name}; use ra_arena::Arena; use ra_syntax::{ ast::{ @@ -12,7 +13,6 @@ use test_utils::tested_by; use crate::{ db::HirDatabase, - name::{AsName, Name, SELF_PARAM}, path::GenericArgs, ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, type_ref::TypeRef, @@ -78,7 +78,7 @@ where let ptr = AstPtr::new(&self_param); let param_pat = self.alloc_pat( Pat::Bind { - name: SELF_PARAM, + name: name::SELF_PARAM, mode: BindingAnnotation::Unannotated, subpat: None, }, diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 697c8dc8490f..b9fbaa367f21 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -1,11 +1,11 @@ //! FIXME: write short doc here +use hir_def::name::AsName; use ra_syntax::ast::{self, AstNode, NameOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, - name::AsName, AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, }; diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 4ce7551c3354..61786a614941 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -5,15 +5,15 @@ use std::sync::Arc; +use hir_def::name::{self, AsName}; use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, - name::SELF_TYPE, path::Path, type_ref::{TypeBound, TypeRef}, - Adt, AsName, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, - Trait, TypeAlias, Union, + Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait, + TypeAlias, Union, }; /// Data about a generic parameter (to a function, struct, impl, ...). @@ -94,11 +94,15 @@ impl GenericParams { GenericDef::Adt(Adt::Enum(it)) => generics.fill(&it.source(db).ast, start), GenericDef::Trait(it) => { // traits get the Self type as an implicit first type parameter - generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None }); + generics.params.push(GenericParam { + idx: start, + name: name::SELF_TYPE, + default: None, + }); generics.fill(&it.source(db).ast, start + 1); // add super traits as bounds on Self // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar - let self_param = TypeRef::Path(SELF_TYPE.into()); + let self_param = TypeRef::Path(name::SELF_TYPE.into()); generics.fill_bounds(&it.source(db).ast, self_param); } GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start), diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index b49f615bf351..6209114593ea 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -36,7 +36,6 @@ mod path; pub mod source_binder; mod ids; -mod name; mod nameres; mod adt; mod traits; @@ -61,7 +60,7 @@ mod marks; use hir_expand::AstId; -use crate::{ids::MacroFileKind, name::AsName, resolve::Resolver}; +use crate::{ids::MacroFileKind, resolve::Resolver}; pub use crate::{ adt::VariantDef, @@ -71,7 +70,6 @@ pub use crate::{ generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, impl_block::ImplBlock, - name::Name, nameres::{ImportId, Namespace, PerNs}, path::{Path, PathKind}, resolve::ScopeDef, @@ -89,3 +87,5 @@ pub use self::code_model::{ Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; + +pub use hir_def::name::Name; diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs deleted file mode 100644 index cf66f88adf7a..000000000000 --- a/crates/ra_hir/src/name.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hir_def::name::*; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 2dd0a5877799..1f3849dc76d1 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir_def::nameres::raw; +use hir_def::{name, nameres::raw}; use ra_cfg::CfgOptions; use ra_db::FileId; use ra_syntax::{ast, SmolStr}; @@ -11,7 +11,6 @@ use crate::{ attr::Attr, db::DefDatabase, ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, - name::MACRO_RULES, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, @@ -726,7 +725,7 @@ where } fn is_macro_rules(path: &Path) -> bool { - path.as_ident() == Some(&MACRO_RULES) + path.as_ident() == Some(&name::MACRO_RULES) } #[cfg(test)] diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 8b62694075df..b9459552b668 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -1,7 +1,10 @@ //! Name resolution. use std::sync::Arc; -use hir_def::CrateModuleId; +use hir_def::{ + name::{self, Name}, + CrateModuleId, +}; use rustc_hash::FxHashSet; use crate::{ @@ -13,7 +16,6 @@ use crate::{ }, generics::GenericParams, impl_block::ImplBlock, - name::{Name, SELF_PARAM, SELF_TYPE}, nameres::{CrateDefMap, PerNs}, path::{Path, PathKind}, Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, @@ -150,13 +152,13 @@ impl Resolver { } } Scope::ImplBlockScope(impl_) => { - if first_name == &SELF_TYPE { + if first_name == &name::SELF_TYPE { let idx = if path.segments.len() == 1 { None } else { Some(1) }; return Some((TypeNs::SelfType(*impl_), idx)); } } Scope::AdtScope(adt) => { - if first_name == &SELF_TYPE { + if first_name == &name::SELF_TYPE { let idx = if path.segments.len() == 1 { None } else { Some(1) }; return Some((TypeNs::AdtSelfType(*adt), idx)); } @@ -205,7 +207,7 @@ impl Resolver { return None; } let n_segments = path.segments.len(); - let tmp = SELF_PARAM; + let tmp = name::SELF_PARAM; let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); for scope in self.scopes.iter().rev() { @@ -241,13 +243,13 @@ impl Resolver { Scope::GenericParams(_) => continue, Scope::ImplBlockScope(impl_) if n_segments > 1 => { - if first_name == &SELF_TYPE { + if first_name == &name::SELF_TYPE { let ty = TypeNs::SelfType(*impl_); return Some(ResolveValueResult::Partial(ty, 1)); } } Scope::AdtScope(adt) if n_segments > 1 => { - if first_name == &SELF_TYPE { + if first_name == &name::SELF_TYPE { let ty = TypeNs::AdtSelfType(*adt); return Some(ResolveValueResult::Partial(ty, 1)); } @@ -459,10 +461,10 @@ impl Scope { } } Scope::ImplBlockScope(i) => { - f(SELF_TYPE, ScopeDef::ImplSelfType(*i)); + f(name::SELF_TYPE, ScopeDef::ImplSelfType(*i)); } Scope::AdtScope(i) => { - f(SELF_TYPE, ScopeDef::AdtSelfType(*i)); + f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i)); } Scope::ExprScope(e) => { e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 730c3322647e..8a1fa29a42c2 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,6 +7,7 @@ //! purely for "IDE needs". use std::sync::Arc; +use hir_def::name::AsName; use ra_db::FileId; use ra_syntax::{ ast::{self, AstNode}, @@ -27,8 +28,8 @@ use crate::{ path::known, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::implements_trait, - AsName, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, - Module, Name, Path, Resolver, Static, Struct, Ty, + Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, Module, + Name, Path, Resolver, Static, Struct, Ty, }; fn try_get_resolver_for_node( diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs index 22f1880493f9..514c813ab1c9 100644 --- a/crates/ra_hir/src/traits.rs +++ b/crates/ra_hir/src/traits.rs @@ -1,14 +1,14 @@ //! HIR for trait definitions. -use rustc_hash::FxHashMap; use std::sync::Arc; +use hir_def::name::AsName; use ra_syntax::ast::{self, NameOwner}; +use rustc_hash::FxHashMap; use crate::{ db::{AstDatabase, DefDatabase}, ids::LocationCtx, - name::AsName, AssocItem, Const, Function, HasSource, Module, Name, Trait, TypeAlias, }; diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 02492ca14507..03c45546d2df 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -5,10 +5,11 @@ use std::iter::successors; +use hir_def::name; use log::{info, warn}; use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; -use crate::{db::HirDatabase, name, HasGenericParams, Resolver}; +use crate::{db::HirDatabase, HasGenericParams, Resolver}; const AUTODEREF_RECURSION_LIMIT: usize = 10; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index ebaff998ee75..92b8e718ea09 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -21,6 +21,7 @@ use std::sync::Arc; use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHashMap; +use hir_def::name; use ra_arena::map::ArenaMap; use ra_prof::profile; use test_utils::tested_by; @@ -37,7 +38,6 @@ use crate::{ db::HirDatabase, diagnostics::DiagnosticSink, expr::{BindingAnnotation, Body, ExprId, PatId}, - name, path::known, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index f8807c742881..7ef87bfe2a94 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -3,12 +3,13 @@ use std::iter::{repeat, repeat_with}; use std::sync::Arc; +use hir_def::name; + use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; use crate::{ db::HirDatabase, expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::{GenericParams, HasGenericParams}, - name, nameres::Namespace, path::{GenericArg, GenericArgs}, ty::{ diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index ab66515beecf..2dd4c2fae529 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -9,6 +9,7 @@ use chalk_ir::{ }; use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; +use hir_def::name; use ra_db::salsa::{InternId, InternKey}; use super::{Canonical, ChalkContext, Impl, Obligation}; @@ -734,7 +735,7 @@ fn closure_fn_trait_impl_datum( substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), }; - let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; + let output_ty_id = fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?; let output_ty_value = chalk_rust_ir::AssociatedTyValue { associated_ty_id: output_ty_id.to_chalk(db), diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs index 674a46102044..18c01e1b9255 100644 --- a/crates/ra_hir/src/type_alias.rs +++ b/crates/ra_hir/src/type_alias.rs @@ -2,11 +2,11 @@ use std::sync::Arc; +use hir_def::name::{AsName, Name}; use ra_syntax::ast::NameOwner; use crate::{ db::{AstDatabase, DefDatabase}, - name::{AsName, Name}, type_ref::TypeRef, HasSource, TypeAlias, }; From e56433432057712086ca623c4a1ef40089004839 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 17:24:36 +0300 Subject: [PATCH 082/102] remove forward pointer to Path --- crates/ra_hir/src/expr.rs | 2 +- crates/ra_hir/src/expr/lower.rs | 6 ++++-- crates/ra_hir/src/expr/validation.rs | 2 +- crates/ra_hir/src/generics.rs | 6 ++++-- crates/ra_hir/src/lib.rs | 7 ++++--- crates/ra_hir/src/path.rs | 1 - crates/ra_hir/src/resolve.rs | 2 +- crates/ra_hir/src/source_binder.rs | 3 +-- crates/ra_hir/src/ty/infer.rs | 3 +-- crates/ra_hir/src/ty/infer/expr.rs | 6 ++++-- crates/ra_hir/src/ty/infer/path.rs | 6 ++++-- crates/ra_hir/src/ty/lower.rs | 3 ++- 12 files changed, 27 insertions(+), 20 deletions(-) delete mode 100644 crates/ra_hir/src/path.rs diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index d238741babe8..31857ad56e94 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -6,13 +6,13 @@ pub(crate) mod validation; use std::{ops::Index, sync::Arc}; +use hir_def::path::GenericArgs; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_syntax::{ast, AstPtr}; use rustc_hash::FxHashMap; use crate::{ db::HirDatabase, - path::GenericArgs, ty::primitive::{UncertainFloatTy, UncertainIntTy}, type_ref::{Mutability, TypeRef}, DefWithBody, Either, HasSource, Name, Path, Resolver, Source, diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index cf8a41b1e862..6436c3a24855 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,6 +1,9 @@ //! FIXME: write short doc here -use hir_def::name::{self, AsName, Name}; +use hir_def::{ + name::{self, AsName, Name}, + path::GenericArgs, +}; use ra_arena::Arena; use ra_syntax::{ ast::{ @@ -13,7 +16,6 @@ use test_utils::tested_by; use crate::{ db::HirDatabase, - path::GenericArgs, ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, type_ref::TypeRef, AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 1aa853c3e96c..c685edda193f 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs @@ -2,6 +2,7 @@ use std::sync::Arc; +use hir_def::path::known; use ra_syntax::ast; use rustc_hash::FxHashSet; @@ -9,7 +10,6 @@ use crate::{ db::HirDatabase, diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, expr::AstPtr, - path::known, ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, Adt, Function, Name, Path, }; diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 61786a614941..45f9713a0a86 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -5,12 +5,14 @@ use std::sync::Arc; -use hir_def::name::{self, AsName}; +use hir_def::{ + name::{self, AsName}, + path::Path, +}; use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, - path::Path, type_ref::{TypeBound, TypeRef}, Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait, TypeAlias, Union, diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 6209114593ea..e723a1f404a2 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -32,7 +32,6 @@ pub mod debug; pub mod db; #[macro_use] pub mod mock; -mod path; pub mod source_binder; mod ids; @@ -71,7 +70,6 @@ pub use crate::{ ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, impl_block::ImplBlock, nameres::{ImportId, Namespace, PerNs}, - path::{Path, PathKind}, resolve::ScopeDef, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, ty::{ @@ -88,4 +86,7 @@ pub use self::code_model::{ ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; -pub use hir_def::name::Name; +pub use hir_def::{ + name::Name, + path::{Path, PathKind}, +}; diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs deleted file mode 100644 index 7f0ff4bfc773..000000000000 --- a/crates/ra_hir/src/path.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hir_def::path::*; diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index b9459552b668..2a783b61e3bb 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use hir_def::{ name::{self, Name}, + path::{Path, PathKind}, CrateModuleId, }; use rustc_hash::FxHashSet; @@ -17,7 +18,6 @@ use crate::{ generics::GenericParams, impl_block::ImplBlock, nameres::{CrateDefMap, PerNs}, - path::{Path, PathKind}, Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, }; diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 8a1fa29a42c2..544433a0ab20 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,7 +7,7 @@ //! purely for "IDE needs". use std::sync::Arc; -use hir_def::name::AsName; +use hir_def::{name::AsName, path::known}; use ra_db::FileId; use ra_syntax::{ ast::{self, AstNode}, @@ -25,7 +25,6 @@ use crate::{ BodySourceMap, }, ids::LocationCtx, - path::known, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::implements_trait, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, Module, diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 92b8e718ea09..05c6b5aad338 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHashMap; -use hir_def::name; +use hir_def::{name, path::known}; use ra_arena::map::ArenaMap; use ra_prof::profile; use test_utils::tested_by; @@ -38,7 +38,6 @@ use crate::{ db::HirDatabase, diagnostics::DiagnosticSink, expr::{BindingAnnotation, Body, ExprId, PatId}, - path::known, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, type_ref::{Mutability, TypeRef}, diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index 7ef87bfe2a94..bc6437b44822 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -3,7 +3,10 @@ use std::iter::{repeat, repeat_with}; use std::sync::Arc; -use hir_def::name; +use hir_def::{ + name, + path::{GenericArg, GenericArgs}, +}; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; use crate::{ @@ -11,7 +14,6 @@ use crate::{ expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::{GenericParams, HasGenericParams}, nameres::Namespace, - path::{GenericArg, GenericArgs}, ty::{ autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index db979353a09a..77aa35ce1330 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs @@ -1,5 +1,7 @@ //! Path expression resolution. +use hir_def::path::PathSegment; + use super::{ExprOrPatId, InferenceContext, TraitRef}; use crate::{ db::HirDatabase, @@ -131,7 +133,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_trait_assoc_item( &mut self, trait_ref: TraitRef, - segment: &crate::path::PathSegment, + segment: &PathSegment, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { let trait_ = trait_ref.trait_; @@ -170,7 +172,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn resolve_ty_assoc_item( &mut self, ty: Ty, - segment: &crate::path::PathSegment, + segment: &PathSegment, id: ExprOrPatId, ) -> Option<(ValueNs, Option)> { if let Ty::Unknown = ty { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 366556134b2a..b131b306c280 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -8,6 +8,8 @@ use std::iter; use std::sync::Arc; +use hir_def::path::{GenericArg, PathSegment}; + use super::{ FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, @@ -18,7 +20,6 @@ use crate::{ generics::HasGenericParams, generics::{GenericDef, WherePredicate}, nameres::Namespace, - path::{GenericArg, PathSegment}, resolve::{Resolver, TypeNs}, ty::Adt, type_ref::{TypeBound, TypeRef}, From e5300ad3baf80c9903235a98a12b6cfd409e9f10 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 17:28:30 +0300 Subject: [PATCH 083/102] remove forward pointer for type_ref --- crates/ra_hir/src/adt.rs | 3 +-- crates/ra_hir/src/code_model.rs | 3 +-- crates/ra_hir/src/expr.rs | 6 ++++-- crates/ra_hir/src/expr/lower.rs | 2 +- crates/ra_hir/src/generics.rs | 2 +- crates/ra_hir/src/impl_block.rs | 2 +- crates/ra_hir/src/lib.rs | 3 +-- crates/ra_hir/src/ty.rs | 4 ++-- crates/ra_hir/src/ty/infer.rs | 7 +++++-- crates/ra_hir/src/ty/infer/coerce.rs | 3 +-- crates/ra_hir/src/ty/lower.rs | 6 ++++-- crates/ra_hir/src/ty/method_resolution.rs | 3 +-- crates/ra_hir/src/type_alias.rs | 6 ++++-- crates/ra_hir/src/type_ref.rs | 1 - 14 files changed, 27 insertions(+), 24 deletions(-) delete mode 100644 crates/ra_hir/src/type_ref.rs diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index ce64980bbceb..d16b3a1cced2 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,13 +3,12 @@ use std::sync::Arc; -use hir_def::name::AsName; +use hir_def::{name::AsName, type_ref::TypeRef}; use ra_arena::{impl_arena_id, Arena, RawId}; use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, - type_ref::TypeRef, Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField, }; diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 7848d0a3f628..d865c972e3f9 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -10,6 +10,7 @@ use hir_def::{ self, AsName, BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, U32, U64, U8, USIZE, }, + type_ref::{Mutability, TypeRef}, CrateModuleId, ModuleId, }; use ra_db::{CrateId, Edition}; @@ -33,8 +34,6 @@ use crate::{ primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, InferenceResult, TraitRef, }, - type_ref::Mutability, - type_ref::TypeRef, Either, HasSource, Name, Ty, }; diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 31857ad56e94..6e23197a4d1c 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -6,7 +6,10 @@ pub(crate) mod validation; use std::{ops::Index, sync::Arc}; -use hir_def::path::GenericArgs; +use hir_def::{ + path::GenericArgs, + type_ref::{Mutability, TypeRef}, +}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_syntax::{ast, AstPtr}; use rustc_hash::FxHashMap; @@ -14,7 +17,6 @@ use rustc_hash::FxHashMap; use crate::{ db::HirDatabase, ty::primitive::{UncertainFloatTy, UncertainIntTy}, - type_ref::{Mutability, TypeRef}, DefWithBody, Either, HasSource, Name, Path, Resolver, Source, }; diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 6436c3a24855..ad029b868f94 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -3,6 +3,7 @@ use hir_def::{ name::{self, AsName, Name}, path::GenericArgs, + type_ref::TypeRef, }; use ra_arena::Arena; use ra_syntax::{ @@ -17,7 +18,6 @@ use test_utils::tested_by; use crate::{ db::HirDatabase, ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, - type_ref::TypeRef, AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver, Source, }; diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 45f9713a0a86..9d5d18564838 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -8,12 +8,12 @@ use std::sync::Arc; use hir_def::{ name::{self, AsName}, path::Path, + type_ref::{TypeBound, TypeRef}, }; use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, - type_ref::{TypeBound, TypeRef}, Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait, TypeAlias, Union, }; diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 06f21fc33eee..8584686fd0cc 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -3,6 +3,7 @@ use rustc_hash::FxHashMap; use std::sync::Arc; +use hir_def::type_ref::TypeRef; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_cfg::CfgOptions; use ra_syntax::{ @@ -19,7 +20,6 @@ use crate::{ ids::MacroCallLoc, resolve::Resolver, ty::Ty, - type_ref::TypeRef, AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef, TypeAlias, }; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index e723a1f404a2..4dd99c74f51e 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -39,7 +39,6 @@ mod nameres; mod adt; mod traits; mod type_alias; -mod type_ref; mod ty; mod attr; mod impl_block; @@ -75,7 +74,6 @@ pub use crate::{ ty::{ display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, - type_ref::Mutability, }; pub use self::code_model::{ @@ -89,4 +87,5 @@ pub use self::code_model::{ pub use hir_def::{ name::Name, path::{Path, PathKind}, + type_ref::Mutability, }; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index cc9746f6d752..d2bfcdc7dbcb 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -17,8 +17,8 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use crate::{ - db::HirDatabase, expr::ExprId, type_ref::Mutability, util::make_mut_slice, Adt, Crate, - DefWithBody, GenericParams, HasGenericParams, Name, Trait, TypeAlias, + db::HirDatabase, expr::ExprId, util::make_mut_slice, Adt, Crate, DefWithBody, GenericParams, + HasGenericParams, Mutability, Name, Trait, TypeAlias, }; use display::{HirDisplay, HirFormatter}; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 05c6b5aad338..7466ee341389 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -21,7 +21,11 @@ use std::sync::Arc; use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHashMap; -use hir_def::{name, path::known}; +use hir_def::{ + name, + path::known, + type_ref::{Mutability, TypeRef}, +}; use ra_arena::map::ArenaMap; use ra_prof::profile; use test_utils::tested_by; @@ -40,7 +44,6 @@ use crate::{ expr::{BindingAnnotation, Body, ExprId, PatId}, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, - type_ref::{Mutability, TypeRef}, Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Path, StructField, }; diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs index 0429a986640e..6ea135126a5c 100644 --- a/crates/ra_hir/src/ty/infer/coerce.rs +++ b/crates/ra_hir/src/ty/infer/coerce.rs @@ -14,8 +14,7 @@ use crate::{ lang_item::LangItemTarget, resolve::Resolver, ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk}, - type_ref::Mutability, - Adt, + Adt, Mutability, }; impl<'a, D: HirDatabase> InferenceContext<'a, D> { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index b131b306c280..0f49a0e541df 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -8,7 +8,10 @@ use std::iter; use std::sync::Arc; -use hir_def::path::{GenericArg, PathSegment}; +use hir_def::{ + path::{GenericArg, PathSegment}, + type_ref::{TypeBound, TypeRef}, +}; use super::{ FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, @@ -22,7 +25,6 @@ use crate::{ nameres::Namespace, resolve::{Resolver, TypeNs}, ty::Adt, - type_ref::{TypeBound, TypeRef}, util::make_mut_slice, BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, TypeAlias, Union, diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 50583a1429e6..eb69344f6a74 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -15,8 +15,7 @@ use crate::{ resolve::Resolver, ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, ty::{Ty, TypeCtor}, - type_ref::Mutability, - AssocItem, Crate, Function, Module, Name, Trait, + AssocItem, Crate, Function, Module, Mutability, Name, Trait, }; /// This is used as a key for indexing impls. diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs index 18c01e1b9255..87126ee7f412 100644 --- a/crates/ra_hir/src/type_alias.rs +++ b/crates/ra_hir/src/type_alias.rs @@ -2,12 +2,14 @@ use std::sync::Arc; -use hir_def::name::{AsName, Name}; +use hir_def::{ + name::{AsName, Name}, + type_ref::TypeRef, +}; use ra_syntax::ast::NameOwner; use crate::{ db::{AstDatabase, DefDatabase}, - type_ref::TypeRef, HasSource, TypeAlias, }; diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs deleted file mode 100644 index bd56ddbe61ae..000000000000 --- a/crates/ra_hir/src/type_ref.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hir_def::type_ref::*; From c1ed9ccc4ed7dfff3abb6eb01d7c311c8e31108c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 17:40:13 +0300 Subject: [PATCH 084/102] fix compilation --- crates/ra_hir/src/db.rs | 7 +++++-- crates/ra_hir/src/either.rs | 1 - crates/ra_hir/src/lib.rs | 3 +-- crates/ra_hir/src/mock.rs | 2 +- crates/ra_hir_def/src/nameres.rs | 2 ++ crates/ra_hir_def/src/nameres/raw.rs | 4 ++-- crates/ra_ide_api/src/db.rs | 1 + 7 files changed, 12 insertions(+), 8 deletions(-) delete mode 100644 crates/ra_hir/src/either.rs diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 142d7338df8d..ebfd970ebc44 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -23,7 +23,10 @@ use crate::{ Struct, StructField, Trait, TypeAlias, }; -pub use hir_def::db::{InternDatabase, InternDatabaseStorage}; +pub use hir_def::db::{ + DefDatabase2, DefDatabase2Storage, InternDatabase, InternDatabaseStorage, RawItemsQuery, + RawItemsWithSourceMapQuery, +}; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, @@ -32,7 +35,7 @@ pub use hir_expand::db::{ // This database uses `AstDatabase` internally, #[salsa::query_group(DefDatabaseStorage)] #[salsa::requires(AstDatabase)] -pub trait DefDatabase: HirDebugDatabase + hir_def::db::DefDatabase2 { +pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { #[salsa::invoke(crate::adt::StructData::struct_data_query)] fn struct_data(&self, s: Struct) -> Arc; diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs deleted file mode 100644 index 44498dd388c4..000000000000 --- a/crates/ra_hir/src/either.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hir_def::either::*; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 4dd99c74f51e..fabe6eff66fa 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -26,7 +26,6 @@ macro_rules! impl_froms { } } -mod either; pub mod debug; pub mod db; @@ -62,7 +61,6 @@ use crate::{ids::MacroFileKind, resolve::Resolver}; pub use crate::{ adt::VariantDef, - either::Either, expr::ExprScopes, from_source::FromSource, generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, @@ -85,6 +83,7 @@ pub use self::code_model::{ }; pub use hir_def::{ + either::Either, name::Name, path::{Path, PathKind}, type_ref::Mutability, diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index bb2d78abe2f0..35dfaf3bad0e 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -17,12 +17,12 @@ use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; pub const WORKSPACE: SourceRootId = SourceRootId(0); #[salsa::database( - hir_def::db::DefDatabase2Storage, ra_db::SourceDatabaseExtStorage, ra_db::SourceDatabaseStorage, db::InternDatabaseStorage, db::AstDatabaseStorage, db::DefDatabaseStorage, + db::DefDatabase2Storage, db::HirDatabaseStorage )] #[derive(Debug)] diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 1a3f7667d2a2..5893708e8ba0 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -1 +1,3 @@ +//! FIXME: write short doc here + pub mod raw; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 13b9fbf48f61..86b4fef9659b 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -8,7 +8,6 @@ use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, AstNode, AstPtr, SourceFile, }; -use test_utils::tested_by; use crate::{ attr::Attr, @@ -301,7 +300,8 @@ impl RawItemsCollector<&DB> { self.push_item(current_module, attrs, RawItemKind::Module(item)); return; } - tested_by!(name_res_works_for_broken_modules); + // FIXME: restore this mark once we complete hir splitting + // tested_by!(name_res_works_for_broken_modules); } fn add_use_item(&mut self, current_module: Option, use_item: ast::UseItem) { diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index 9146b647a8e3..785e71808b7c 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs @@ -23,6 +23,7 @@ use crate::{ hir::db::InternDatabaseStorage, hir::db::AstDatabaseStorage, hir::db::DefDatabaseStorage, + hir::db::DefDatabase2Storage, hir::db::HirDatabaseStorage )] #[derive(Debug)] From e34e71c62d9b4cf0ab237969e03ecde893ab347b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 18:06:08 +0300 Subject: [PATCH 085/102] remove forward pointer for attrs --- crates/ra_hir/src/attr.rs | 1 - crates/ra_hir/src/impl_block.rs | 3 +-- crates/ra_hir/src/lib.rs | 1 - crates/ra_hir/src/nameres/collector.rs | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 crates/ra_hir/src/attr.rs diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs deleted file mode 100644 index 988a671b81b2..000000000000 --- a/crates/ra_hir/src/attr.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hir_def::attr::*; diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 8584686fd0cc..518330713217 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -3,7 +3,7 @@ use rustc_hash::FxHashMap; use std::sync::Arc; -use hir_def::type_ref::TypeRef; +use hir_def::{attr::Attr, type_ref::TypeRef}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_cfg::CfgOptions; use ra_syntax::{ @@ -12,7 +12,6 @@ use ra_syntax::{ }; use crate::{ - attr::Attr, code_model::{Module, ModuleSource}, db::{AstDatabase, DefDatabase, HirDatabase}, generics::HasGenericParams, diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index fabe6eff66fa..f765490b0117 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -39,7 +39,6 @@ mod adt; mod traits; mod type_alias; mod ty; -mod attr; mod impl_block; mod expr; mod lang_item; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 1f3849dc76d1..2f342870b136 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir_def::{name, nameres::raw}; +use hir_def::{attr::Attr, name, nameres::raw}; use ra_cfg::CfgOptions; use ra_db::FileId; use ra_syntax::{ast, SmolStr}; @@ -8,7 +8,6 @@ use rustc_hash::FxHashMap; use test_utils::tested_by; use crate::{ - attr::Attr, db::DefDatabase, ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, nameres::{ From 0bc7d285189caaffc13e4d6856baf895f72ed80c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 18:41:50 +0300 Subject: [PATCH 086/102] refactor $crate handling Introduce proper hygiene module, which should grow quite a bit eventually. --- crates/ra_hir/src/expr/lower.rs | 4 +- crates/ra_hir/src/impl_block.rs | 12 ++-- crates/ra_hir_def/src/attr.rs | 18 ++--- crates/ra_hir_def/src/hygiene.rs | 40 +++++++++++ crates/ra_hir_def/src/lib.rs | 1 + crates/ra_hir_def/src/nameres/raw.rs | 31 ++++---- crates/ra_hir_def/src/path.rs | 101 +++++++++++++-------------- 7 files changed, 118 insertions(+), 89 deletions(-) create mode 100644 crates/ra_hir_def/src/hygiene.rs diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index ad029b868f94..575d78198c49 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,6 +1,7 @@ //! FIXME: write short doc here use hir_def::{ + hygiene::Hygiene, name::{self, AsName, Name}, path::GenericArgs, type_ref::TypeRef, @@ -597,7 +598,8 @@ where } fn parse_path(&mut self, path: ast::Path) -> Option { - Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db) + let hygiene = Hygiene::new(self.db, self.current_file_id); + Path::from_src(path, &hygiene) } } diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 518330713217..9e4a4001770f 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -3,7 +3,7 @@ use rustc_hash::FxHashMap; use std::sync::Arc; -use hir_def::{attr::Attr, type_ref::TypeRef}; +use hir_def::{attr::Attr, hygiene::Hygiene, type_ref::TypeRef}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_cfg::CfgOptions; use ra_syntax::{ @@ -227,10 +227,11 @@ impl ModuleImplBlocks { owner: &dyn ast::ModuleItemOwner, file_id: HirFileId, ) { + let hygiene = Hygiene::new(db, file_id); for item in owner.items_with_macros() { match item { ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { - let attrs = Attr::from_attrs_owner(file_id, &impl_block_ast, db); + let attrs = Attr::from_attrs_owner(&impl_block_ast, &hygiene); if attrs.map_or(false, |attrs| { attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) }) { @@ -247,7 +248,7 @@ impl ModuleImplBlocks { } ast::ItemOrMacro::Item(_) => (), ast::ItemOrMacro::Macro(macro_call) => { - let attrs = Attr::from_attrs_owner(file_id, ¯o_call, db); + let attrs = Attr::from_attrs_owner(¯o_call, &hygiene); if attrs.map_or(false, |attrs| { attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) }) { @@ -256,9 +257,8 @@ impl ModuleImplBlocks { //FIXME: we should really cut down on the boilerplate required to process a macro let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_call)); - if let Some(path) = macro_call - .path() - .and_then(|path| Path::from_src(Source { ast: path, file_id }, db)) + if let Some(path) = + macro_call.path().and_then(|path| Path::from_src(path, &hygiene)) { if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) { diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 248f03cdfdd4..71f92adc2979 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -2,7 +2,6 @@ use std::sync::Arc; -use hir_expand::db::AstDatabase; use mbe::ast_to_token_tree; use ra_cfg::CfgOptions; use ra_syntax::{ @@ -11,7 +10,7 @@ use ra_syntax::{ }; use tt::Subtree; -use crate::{path::Path, HirFileId, Source}; +use crate::{hygiene::Hygiene, path::Path}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Attr { @@ -26,11 +25,8 @@ pub enum AttrInput { } impl Attr { - pub(crate) fn from_src( - Source { file_id, ast }: Source, - db: &impl AstDatabase, - ) -> Option { - let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?; + pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option { + let path = Path::from_src(ast.path()?, hygiene)?; let input = match ast.input() { None => None, Some(ast::AttrInput::Literal(lit)) => { @@ -46,17 +42,13 @@ impl Attr { Some(Attr { path, input }) } - pub fn from_attrs_owner( - file_id: HirFileId, - owner: &dyn AttrsOwner, - db: &impl AstDatabase, - ) -> Option> { + pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Option> { let mut attrs = owner.attrs().peekable(); if attrs.peek().is_none() { // Avoid heap allocation return None; } - Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) + Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) } pub fn is_simple_atom(&self, name: &str) -> bool { diff --git a/crates/ra_hir_def/src/hygiene.rs b/crates/ra_hir_def/src/hygiene.rs new file mode 100644 index 000000000000..e1ae58a3bc9a --- /dev/null +++ b/crates/ra_hir_def/src/hygiene.rs @@ -0,0 +1,40 @@ +//! This modules handles hygiene information. +//! +//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at +//! this moment, this is horribly incomplete and handles only `$crate`. +// Should this be moved to `hir_expand`? Seems like it. + +use hir_expand::{db::AstDatabase, HirFileId}; +use ra_db::CrateId; +use ra_syntax::ast; + +use crate::{ + either::Either, + name::{AsName, Name}, +}; + +#[derive(Debug)] +pub struct Hygiene { + // This is what `$crate` expands to + def_crate: Option, +} + +impl Hygiene { + pub fn new(db: &impl AstDatabase, file_id: HirFileId) -> Hygiene { + Hygiene { def_crate: file_id.macro_crate(db) } + } + + pub(crate) fn new_unhygienic() -> Hygiene { + Hygiene { def_crate: None } + } + + // FIXME: this should just return name + pub(crate) fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either { + if let Some(def_crate) = self.def_crate { + if name_ref.text() == "$crate" { + return Either::B(def_crate); + } + } + Either::A(name_ref.as_name()) + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 95d50332568a..61ccdb30d2c5 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -13,6 +13,7 @@ pub mod attr; pub mod name; pub mod path; pub mod type_ref; +pub mod hygiene; // FIXME: this should be private pub mod nameres; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 86b4fef9659b..636364628b24 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -13,6 +13,7 @@ use crate::{ attr::Attr, db::DefDatabase2, either::Either, + hygiene::Hygiene, name::{AsName, Name}, path::Path, FileAstId, HirFileId, ModuleSource, Source, @@ -78,7 +79,7 @@ impl RawItems { source_ast_id_map: db.ast_id_map(file_id), source_map: ImportSourceMap::default(), file_id, - db, + hygiene: Hygiene::new(db, file_id), }; if let Some(node) = db.parse_or_expand(file_id) { if let Some(source_file) = ast::SourceFile::cast(node.clone()) { @@ -204,15 +205,15 @@ pub struct MacroData { pub export: bool, } -struct RawItemsCollector { +struct RawItemsCollector { raw_items: RawItems, source_ast_id_map: Arc, source_map: ImportSourceMap, file_id: HirFileId, - db: DB, + hygiene: Hygiene, } -impl RawItemsCollector<&DB> { +impl RawItemsCollector { fn process_module(&mut self, current_module: Option, body: impl ast::ModuleItemOwner) { for item_or_macro in body.items_with_macros() { match item_or_macro { @@ -309,9 +310,10 @@ impl RawItemsCollector<&DB> { let is_prelude = use_item.has_atom_attr("prelude_import"); let attrs = self.parse_attrs(&use_item); + let mut buf = Vec::new(); Path::expand_use_item( Source { ast: use_item, file_id: self.file_id }, - self.db, + &self.hygiene, |path, use_tree, is_glob, alias| { let import_data = ImportData { path, @@ -321,14 +323,12 @@ impl RawItemsCollector<&DB> { is_extern_crate: false, is_macro_use: false, }; - self.push_import( - current_module, - attrs.clone(), - import_data, - Either::A(AstPtr::new(use_tree)), - ); + buf.push((import_data, Either::A(AstPtr::new(use_tree)))); }, - ) + ); + for (import_data, ptr) in buf { + self.push_import(current_module, attrs.clone(), import_data, ptr); + } } fn add_extern_crate_item( @@ -361,10 +361,7 @@ impl RawItemsCollector<&DB> { fn add_macro(&mut self, current_module: Option, m: ast::MacroCall) { let attrs = self.parse_attrs(&m); - let path = match m - .path() - .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) - { + let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { Some(it) => it, _ => return, }; @@ -402,6 +399,6 @@ impl RawItemsCollector<&DB> { } fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { - Attr::from_attrs_owner(self.file_id, item, self.db) + Attr::from_attrs_owner(item, &self.hygiene) } } diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index fe060437df8f..39f394c3f758 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -2,7 +2,6 @@ use std::{iter, sync::Arc}; -use hir_expand::db::AstDatabase; use ra_db::CrateId; use ra_syntax::{ ast::{self, NameOwner, TypeAscriptionOwner}, @@ -10,6 +9,8 @@ use ra_syntax::{ }; use crate::{ + either::Either, + hygiene::Hygiene, name::{self, AsName, Name}, type_ref::TypeRef, Source, @@ -68,11 +69,11 @@ impl Path { /// Calls `cb` with all paths, represented by this use item. pub fn expand_use_item( item_src: Source, - db: &impl AstDatabase, + hygiene: &Hygiene, mut cb: impl FnMut(Path, &ast::UseTree, bool, Option), ) { if let Some(tree) = item_src.ast.use_tree() { - expand_use_tree(None, tree, &|| item_src.file_id.macro_crate(db), &mut cb); + expand_use_tree(None, tree, hygiene, &mut cb); } } @@ -89,17 +90,12 @@ impl Path { /// Converts an `ast::Path` to `Path`. Works with use trees. /// DEPRECATED: It does not handle `$crate` from macro call. pub fn from_ast(path: ast::Path) -> Option { - Path::parse(path, &|| None) + Path::from_src(path, &Hygiene::new_unhygienic()) } /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. - pub fn from_src(source: Source, db: &impl AstDatabase) -> Option { - let file_id = source.file_id; - Path::parse(source.ast, &|| file_id.macro_crate(db)) - } - - fn parse(mut path: ast::Path, macro_crate: &impl Fn() -> Option) -> Option { + pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option { let mut kind = PathKind::Plain; let mut segments = Vec::new(); loop { @@ -110,26 +106,28 @@ impl Path { } match segment.kind()? { - ast::PathSegmentKind::Name(name) => { - if name.text() == "$crate" { - if let Some(macro_crate) = macro_crate() { - kind = PathKind::DollarCrate(macro_crate); + ast::PathSegmentKind::Name(name_ref) => { + // FIXME: this should just return name + match hygiene.name_ref_to_name(name_ref) { + Either::A(name) => { + let args = segment + .type_arg_list() + .and_then(GenericArgs::from_ast) + .or_else(|| { + GenericArgs::from_fn_like_path_ast( + segment.param_list(), + segment.ret_type(), + ) + }) + .map(Arc::new); + let segment = PathSegment { name, args_and_bindings: args }; + segments.push(segment); + } + Either::B(crate_id) => { + kind = PathKind::DollarCrate(crate_id); break; } } - - let args = segment - .type_arg_list() - .and_then(GenericArgs::from_ast) - .or_else(|| { - GenericArgs::from_fn_like_path_ast( - segment.param_list(), - segment.ret_type(), - ) - }) - .map(Arc::new); - let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; - segments.push(segment); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -143,7 +141,7 @@ impl Path { } // >::Foo desugars to Trait::Foo Some(trait_ref) => { - let path = Path::parse(trait_ref.path()?, macro_crate)?; + let path = Path::from_src(trait_ref.path()?, hygiene)?; kind = path.kind; let mut prefix_segments = path.segments; prefix_segments.reverse(); @@ -294,7 +292,7 @@ impl From for Path { fn expand_use_tree( prefix: Option, tree: ast::UseTree, - macro_crate: &impl Fn() -> Option, + hygiene: &Hygiene, cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option), ) { if let Some(use_tree_list) = tree.use_tree_list() { @@ -303,13 +301,13 @@ fn expand_use_tree( None => prefix, // E.g. `use something::{inner}` (prefix is `None`, path is `something`) // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) - Some(path) => match convert_path(prefix, path, macro_crate) { + Some(path) => match convert_path(prefix, path, hygiene) { Some(it) => Some(it), None => return, // FIXME: report errors somewhere }, }; for child_tree in use_tree_list.use_trees() { - expand_use_tree(prefix.clone(), child_tree, macro_crate, cb); + expand_use_tree(prefix.clone(), child_tree, hygiene, cb); } } else { let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name()); @@ -326,7 +324,7 @@ fn expand_use_tree( } } } - if let Some(path) = convert_path(prefix, ast_path, macro_crate) { + if let Some(path) = convert_path(prefix, ast_path, hygiene) { let is_glob = tree.has_star(); cb(path, &tree, is_glob, alias) } @@ -336,37 +334,36 @@ fn expand_use_tree( } } -fn convert_path( - prefix: Option, - path: ast::Path, - macro_crate: &impl Fn() -> Option, -) -> Option { +fn convert_path(prefix: Option, path: ast::Path, hygiene: &Hygiene) -> Option { let prefix = if let Some(qual) = path.qualifier() { - Some(convert_path(prefix, qual, macro_crate)?) + Some(convert_path(prefix, qual, hygiene)?) } else { prefix }; let segment = path.segment()?; let res = match segment.kind()? { - ast::PathSegmentKind::Name(name) => { - if name.text() == "$crate" { - if let Some(krate) = macro_crate() { + ast::PathSegmentKind::Name(name_ref) => { + match hygiene.name_ref_to_name(name_ref) { + Either::A(name) => { + // no type args in use + let mut res = prefix.unwrap_or_else(|| Path { + kind: PathKind::Plain, + segments: Vec::with_capacity(1), + }); + res.segments.push(PathSegment { + name, + args_and_bindings: None, // no type args in use + }); + res + } + Either::B(crate_id) => { return Some(Path::from_simple_segments( - PathKind::DollarCrate(krate), + PathKind::DollarCrate(crate_id), iter::empty(), - )); + )) } } - - // no type args in use - let mut res = prefix - .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); - res.segments.push(PathSegment { - name: name.as_name(), - args_and_bindings: None, // no type args in use - }); - res } ast::PathSegmentKind::CrateKw => { if prefix.is_some() { From b05d6e53fb0e9a008dc2e1220b1201818e63ed2d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 18:50:10 +0300 Subject: [PATCH 087/102] push either to hir_expand --- crates/ra_hir/src/lib.rs | 17 ++++++++--------- crates/ra_hir_def/src/hygiene.rs | 6 ++---- crates/ra_hir_def/src/lib.rs | 1 - crates/ra_hir_def/src/nameres/raw.rs | 11 ++++------- crates/ra_hir_def/src/path.rs | 2 +- .../{ra_hir_def => ra_hir_expand}/src/either.rs | 0 crates/ra_hir_expand/src/lib.rs | 1 + 7 files changed, 16 insertions(+), 22 deletions(-) rename crates/{ra_hir_def => ra_hir_expand}/src/either.rs (100%) diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index f765490b0117..989818c0e984 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -60,6 +60,13 @@ use crate::{ids::MacroFileKind, resolve::Resolver}; pub use crate::{ adt::VariantDef, + code_model::{ + docs::{DocDef, Docs, Documentation}, + src::{HasBodySource, HasSource, Source}, + Adt, AssocItem, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, + DefWithBody, Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, + ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, + }, expr::ExprScopes, from_source::FromSource, generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, @@ -73,17 +80,9 @@ pub use crate::{ }, }; -pub use self::code_model::{ - docs::{DocDef, Docs, Documentation}, - src::{HasBodySource, HasSource, Source}, - Adt, AssocItem, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, - Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, - ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, -}; - pub use hir_def::{ - either::Either, name::Name, path::{Path, PathKind}, type_ref::Mutability, }; +pub use hir_expand::either::Either; diff --git a/crates/ra_hir_def/src/hygiene.rs b/crates/ra_hir_def/src/hygiene.rs index e1ae58a3bc9a..f51c46fcb86b 100644 --- a/crates/ra_hir_def/src/hygiene.rs +++ b/crates/ra_hir_def/src/hygiene.rs @@ -4,14 +4,12 @@ //! this moment, this is horribly incomplete and handles only `$crate`. // Should this be moved to `hir_expand`? Seems like it. +use hir_expand::either::Either; use hir_expand::{db::AstDatabase, HirFileId}; use ra_db::CrateId; use ra_syntax::ast; -use crate::{ - either::Either, - name::{AsName, Name}, -}; +use crate::name::{AsName, Name}; #[derive(Debug)] pub struct Hygiene { diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 61ccdb30d2c5..0de728dc1a17 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -8,7 +8,6 @@ //! actually true. pub mod db; -pub mod either; pub mod attr; pub mod name; pub mod path; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 636364628b24..f1896c0cc087 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -2,7 +2,7 @@ use std::{ops::Index, sync::Arc}; -use hir_expand::{ast_id_map::AstIdMap, db::AstDatabase}; +use hir_expand::{ast_id_map::AstIdMap, db::AstDatabase, either::Either}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, @@ -12,7 +12,6 @@ use ra_syntax::{ use crate::{ attr::Attr, db::DefDatabase2, - either::Either, hygiene::Hygiene, name::{AsName, Name}, path::Path, @@ -41,10 +40,8 @@ pub struct ImportSourceMap { type ImportSourcePtr = Either, AstPtr>; type ImportSource = Either; -impl ImportSourcePtr { - fn to_node(self, file: &SourceFile) -> ImportSource { - self.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax())) - } +fn to_node(ptr: ImportSourcePtr, file: &SourceFile) -> ImportSource { + ptr.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax())) } impl ImportSourceMap { @@ -58,7 +55,7 @@ impl ImportSourceMap { ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), }; - self.map[import].to_node(&file) + to_node(self.map[import], &file) } } diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 39f394c3f758..8d57e7761623 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -2,6 +2,7 @@ use std::{iter, sync::Arc}; +use hir_expand::either::Either; use ra_db::CrateId; use ra_syntax::{ ast::{self, NameOwner, TypeAscriptionOwner}, @@ -9,7 +10,6 @@ use ra_syntax::{ }; use crate::{ - either::Either, hygiene::Hygiene, name::{self, AsName, Name}, type_ref::TypeRef, diff --git a/crates/ra_hir_def/src/either.rs b/crates/ra_hir_expand/src/either.rs similarity index 100% rename from crates/ra_hir_def/src/either.rs rename to crates/ra_hir_expand/src/either.rs diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 3c0ef8f1c05a..6359b2b4d93b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -6,6 +6,7 @@ pub mod db; pub mod ast_id_map; +pub mod either; use std::hash::{Hash, Hasher}; From 872ac566bfc6cf43ac55354cf5223b962dbc1d92 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 18:56:20 +0300 Subject: [PATCH 088/102] push name down to hir_expand --- crates/ra_hir/src/adt.rs | 3 ++- crates/ra_hir/src/code_model.rs | 8 ++++---- crates/ra_hir/src/expr/lower.rs | 8 ++------ crates/ra_hir/src/from_source.rs | 2 +- crates/ra_hir/src/generics.rs | 2 +- crates/ra_hir/src/lib.rs | 3 +-- crates/ra_hir/src/nameres/collector.rs | 3 ++- crates/ra_hir/src/resolve.rs | 2 +- crates/ra_hir/src/source_binder.rs | 3 ++- crates/ra_hir/src/traits.rs | 3 ++- crates/ra_hir/src/ty/autoderef.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 2 +- crates/ra_hir/src/ty/infer/expr.rs | 6 ++---- crates/ra_hir/src/ty/traits/chalk.rs | 3 ++- crates/ra_hir/src/type_alias.rs | 7 +++---- crates/ra_hir_def/src/hygiene.rs | 10 ++++++---- crates/ra_hir_def/src/lib.rs | 1 - crates/ra_hir_def/src/nameres/raw.rs | 15 ++++++++------- crates/ra_hir_def/src/path.rs | 15 +++++++-------- crates/ra_hir_expand/src/lib.rs | 1 + crates/{ra_hir_def => ra_hir_expand}/src/name.rs | 0 21 files changed, 49 insertions(+), 50 deletions(-) rename crates/{ra_hir_def => ra_hir_expand}/src/name.rs (100%) diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index d16b3a1cced2..97424b39e00d 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,7 +3,8 @@ use std::sync::Arc; -use hir_def::{name::AsName, type_ref::TypeRef}; +use hir_def::type_ref::TypeRef; +use hir_expand::name::AsName; use ra_arena::{impl_arena_id, Arena, RawId}; use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index d865c972e3f9..a6ce23dd10e4 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -6,13 +6,13 @@ pub(crate) mod docs; use std::sync::Arc; use hir_def::{ - name::{ - self, AsName, BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, - U16, U32, U64, U8, USIZE, - }, type_ref::{Mutability, TypeRef}, CrateModuleId, ModuleId, }; +use hir_expand::name::{ + self, AsName, BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, + U32, U64, U8, USIZE, +}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 575d78198c49..241ad68fd8b2 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,11 +1,7 @@ //! FIXME: write short doc here -use hir_def::{ - hygiene::Hygiene, - name::{self, AsName, Name}, - path::GenericArgs, - type_ref::TypeRef, -}; +use hir_def::{hygiene::Hygiene, path::GenericArgs, type_ref::TypeRef}; +use hir_expand::name::{self, AsName, Name}; use ra_arena::Arena; use ra_syntax::{ ast::{ diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index b9fbaa367f21..a9de0145538b 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir_def::name::AsName; +use hir_expand::name::AsName; use ra_syntax::ast::{self, AstNode, NameOwner}; use crate::{ diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 9d5d18564838..52e1fbf2946b 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -6,10 +6,10 @@ use std::sync::Arc; use hir_def::{ - name::{self, AsName}, path::Path, type_ref::{TypeBound, TypeRef}, }; +use hir_expand::name::{self, AsName}; use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; use crate::{ diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 989818c0e984..603b0c3dc3f1 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -81,8 +81,7 @@ pub use crate::{ }; pub use hir_def::{ - name::Name, path::{Path, PathKind}, type_ref::Mutability, }; -pub use hir_expand::either::Either; +pub use hir_expand::{either::Either, name::Name}; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 2f342870b136..e2e13805acc0 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,6 +1,7 @@ //! FIXME: write short doc here -use hir_def::{attr::Attr, name, nameres::raw}; +use hir_def::{attr::Attr, nameres::raw}; +use hir_expand::name; use ra_cfg::CfgOptions; use ra_db::FileId; use ra_syntax::{ast, SmolStr}; diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2a783b61e3bb..f77c9df9f023 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -2,10 +2,10 @@ use std::sync::Arc; use hir_def::{ - name::{self, Name}, path::{Path, PathKind}, CrateModuleId, }; +use hir_expand::name::{self, Name}; use rustc_hash::FxHashSet; use crate::{ diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 544433a0ab20..01f51ba5d470 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,7 +7,8 @@ //! purely for "IDE needs". use std::sync::Arc; -use hir_def::{name::AsName, path::known}; +use hir_def::path::known; +use hir_expand::name::AsName; use ra_db::FileId; use ra_syntax::{ ast::{self, AstNode}, diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs index 514c813ab1c9..1a45dacba92d 100644 --- a/crates/ra_hir/src/traits.rs +++ b/crates/ra_hir/src/traits.rs @@ -2,7 +2,8 @@ use std::sync::Arc; -use hir_def::name::AsName; +use hir_expand::name::AsName; + use ra_syntax::ast::{self, NameOwner}; use rustc_hash::FxHashMap; diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 03c45546d2df..3645ee831c91 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -5,7 +5,7 @@ use std::iter::successors; -use hir_def::name; +use hir_expand::name; use log::{info, warn}; use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7466ee341389..6694467a36cb 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -22,10 +22,10 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; use rustc_hash::FxHashMap; use hir_def::{ - name, path::known, type_ref::{Mutability, TypeRef}, }; +use hir_expand::name; use ra_arena::map::ArenaMap; use ra_prof::profile; use test_utils::tested_by; diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index bc6437b44822..fed52df39cef 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -3,10 +3,8 @@ use std::iter::{repeat, repeat_with}; use std::sync::Arc; -use hir_def::{ - name, - path::{GenericArg, GenericArgs}, -}; +use hir_def::path::{GenericArg, GenericArgs}; +use hir_expand::name; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; use crate::{ diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 2dd4c2fae529..39ef9218279e 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -9,7 +9,8 @@ use chalk_ir::{ }; use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; -use hir_def::name; +use hir_expand::name; + use ra_db::salsa::{InternId, InternKey}; use super::{Canonical, ChalkContext, Impl, Obligation}; diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs index 87126ee7f412..078e6295eaa3 100644 --- a/crates/ra_hir/src/type_alias.rs +++ b/crates/ra_hir/src/type_alias.rs @@ -2,10 +2,9 @@ use std::sync::Arc; -use hir_def::{ - name::{AsName, Name}, - type_ref::TypeRef, -}; +use hir_def::type_ref::TypeRef; +use hir_expand::name::{AsName, Name}; + use ra_syntax::ast::NameOwner; use crate::{ diff --git a/crates/ra_hir_def/src/hygiene.rs b/crates/ra_hir_def/src/hygiene.rs index f51c46fcb86b..94de2c57c214 100644 --- a/crates/ra_hir_def/src/hygiene.rs +++ b/crates/ra_hir_def/src/hygiene.rs @@ -4,13 +4,15 @@ //! this moment, this is horribly incomplete and handles only `$crate`. // Should this be moved to `hir_expand`? Seems like it. -use hir_expand::either::Either; -use hir_expand::{db::AstDatabase, HirFileId}; +use hir_expand::{ + db::AstDatabase, + either::Either, + name::{AsName, Name}, + HirFileId, +}; use ra_db::CrateId; use ra_syntax::ast; -use crate::name::{AsName, Name}; - #[derive(Debug)] pub struct Hygiene { // This is what `$crate` expands to diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 0de728dc1a17..5135dda56a21 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -9,7 +9,6 @@ pub mod db; pub mod attr; -pub mod name; pub mod path; pub mod type_ref; pub mod hygiene; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index f1896c0cc087..56831e409fd6 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -2,7 +2,12 @@ use std::{ops::Index, sync::Arc}; -use hir_expand::{ast_id_map::AstIdMap, db::AstDatabase, either::Either}; +use hir_expand::{ + ast_id_map::AstIdMap, + db::AstDatabase, + either::Either, + name::{AsName, Name}, +}; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, @@ -10,12 +15,8 @@ use ra_syntax::{ }; use crate::{ - attr::Attr, - db::DefDatabase2, - hygiene::Hygiene, - name::{AsName, Name}, - path::Path, - FileAstId, HirFileId, ModuleSource, Source, + attr::Attr, db::DefDatabase2, hygiene::Hygiene, path::Path, FileAstId, HirFileId, ModuleSource, + Source, }; /// `RawItems` is a set of top-level items in a file (except for impls). diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 8d57e7761623..d0b842a6b1b0 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -2,19 +2,17 @@ use std::{iter, sync::Arc}; -use hir_expand::either::Either; +use hir_expand::{ + either::Either, + name::{self, AsName, Name}, +}; use ra_db::CrateId; use ra_syntax::{ ast::{self, NameOwner, TypeAscriptionOwner}, AstNode, }; -use crate::{ - hygiene::Hygiene, - name::{self, AsName, Name}, - type_ref::TypeRef, - Source, -}; +use crate::{hygiene::Hygiene, type_ref::TypeRef, Source}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { @@ -392,8 +390,9 @@ fn convert_path(prefix: Option, path: ast::Path, hygiene: &Hygiene) -> Opt } pub mod known { + use hir_expand::name; + use super::{Path, PathKind}; - use crate::name; pub fn std_iter_into_iterator() -> Path { Path::from_simple_segments( diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 6359b2b4d93b..cf28de3d8cc7 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -7,6 +7,7 @@ pub mod db; pub mod ast_id_map; pub mod either; +pub mod name; use std::hash::{Hash, Hasher}; diff --git a/crates/ra_hir_def/src/name.rs b/crates/ra_hir_expand/src/name.rs similarity index 100% rename from crates/ra_hir_def/src/name.rs rename to crates/ra_hir_expand/src/name.rs From ab559f170ee02e3bdd9aeeb55933bb143b520c34 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 19:10:53 +0300 Subject: [PATCH 089/102] move hygiene to hir_expand --- crates/ra_hir/src/expr/lower.rs | 7 ++++-- crates/ra_hir/src/impl_block.rs | 3 ++- crates/ra_hir_def/src/attr.rs | 3 ++- crates/ra_hir_def/src/lib.rs | 1 - crates/ra_hir_def/src/nameres/raw.rs | 6 ++--- crates/ra_hir_def/src/path.rs | 3 ++- .../src/hygiene.rs | 22 ++++++++++++------- crates/ra_hir_expand/src/lib.rs | 12 +--------- 8 files changed, 28 insertions(+), 29 deletions(-) rename crates/{ra_hir_def => ra_hir_expand}/src/hygiene.rs (63%) diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 241ad68fd8b2..6463dd65e1ed 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs @@ -1,7 +1,10 @@ //! FIXME: write short doc here -use hir_def::{hygiene::Hygiene, path::GenericArgs, type_ref::TypeRef}; -use hir_expand::name::{self, AsName, Name}; +use hir_def::{path::GenericArgs, type_ref::TypeRef}; +use hir_expand::{ + hygiene::Hygiene, + name::{self, AsName, Name}, +}; use ra_arena::Arena; use ra_syntax::{ ast::{ diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 9e4a4001770f..b1a0140745c4 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -3,7 +3,8 @@ use rustc_hash::FxHashMap; use std::sync::Arc; -use hir_def::{attr::Attr, hygiene::Hygiene, type_ref::TypeRef}; +use hir_def::{attr::Attr, type_ref::TypeRef}; +use hir_expand::hygiene::Hygiene; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; use ra_cfg::CfgOptions; use ra_syntax::{ diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 71f92adc2979..0e961ca12aff 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -2,6 +2,7 @@ use std::sync::Arc; +use hir_expand::hygiene::Hygiene; use mbe::ast_to_token_tree; use ra_cfg::CfgOptions; use ra_syntax::{ @@ -10,7 +11,7 @@ use ra_syntax::{ }; use tt::Subtree; -use crate::{hygiene::Hygiene, path::Path}; +use crate::path::Path; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Attr { diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 5135dda56a21..7a6c7b30125e 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -11,7 +11,6 @@ pub mod db; pub mod attr; pub mod path; pub mod type_ref; -pub mod hygiene; // FIXME: this should be private pub mod nameres; diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 56831e409fd6..86c05d6028e7 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -6,6 +6,7 @@ use hir_expand::{ ast_id_map::AstIdMap, db::AstDatabase, either::Either, + hygiene::Hygiene, name::{AsName, Name}, }; use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; @@ -14,10 +15,7 @@ use ra_syntax::{ AstNode, AstPtr, SourceFile, }; -use crate::{ - attr::Attr, db::DefDatabase2, hygiene::Hygiene, path::Path, FileAstId, HirFileId, ModuleSource, - Source, -}; +use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source}; /// `RawItems` is a set of top-level items in a file (except for impls). /// diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index d0b842a6b1b0..ddabc7ca6687 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -4,6 +4,7 @@ use std::{iter, sync::Arc}; use hir_expand::{ either::Either, + hygiene::Hygiene, name::{self, AsName, Name}, }; use ra_db::CrateId; @@ -12,7 +13,7 @@ use ra_syntax::{ AstNode, }; -use crate::{hygiene::Hygiene, type_ref::TypeRef, Source}; +use crate::{type_ref::TypeRef, Source}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { diff --git a/crates/ra_hir_def/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs similarity index 63% rename from crates/ra_hir_def/src/hygiene.rs rename to crates/ra_hir_expand/src/hygiene.rs index 94de2c57c214..77428ec99049 100644 --- a/crates/ra_hir_def/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -2,16 +2,15 @@ //! //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at //! this moment, this is horribly incomplete and handles only `$crate`. -// Should this be moved to `hir_expand`? Seems like it. +use ra_db::CrateId; +use ra_syntax::ast; -use hir_expand::{ +use crate::{ db::AstDatabase, either::Either, name::{AsName, Name}, - HirFileId, + HirFileId, HirFileIdRepr, }; -use ra_db::CrateId; -use ra_syntax::ast; #[derive(Debug)] pub struct Hygiene { @@ -21,15 +20,22 @@ pub struct Hygiene { impl Hygiene { pub fn new(db: &impl AstDatabase, file_id: HirFileId) -> Hygiene { - Hygiene { def_crate: file_id.macro_crate(db) } + let def_crate = match file_id.0 { + HirFileIdRepr::FileId(_) => None, + HirFileIdRepr::MacroFile(macro_file) => { + let loc = db.lookup_intern_macro(macro_file.macro_call_id); + Some(loc.def.krate) + } + }; + Hygiene { def_crate } } - pub(crate) fn new_unhygienic() -> Hygiene { + pub fn new_unhygienic() -> Hygiene { Hygiene { def_crate: None } } // FIXME: this should just return name - pub(crate) fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either { + pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either { if let Some(def_crate) = self.def_crate { if name_ref.text() == "$crate" { return Either::B(def_crate); diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index cf28de3d8cc7..5a0e5a19c533 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -8,6 +8,7 @@ pub mod db; pub mod ast_id_map; pub mod either; pub mod name; +pub mod hygiene; use std::hash::{Hash, Hasher}; @@ -61,17 +62,6 @@ impl HirFileId { } } } - - /// Get the crate which the macro lives in, if it is a macro file. - pub fn macro_crate(self, db: &dyn db::AstDatabase) -> Option { - match self.0 { - HirFileIdRepr::FileId(_) => None, - HirFileIdRepr::MacroFile(macro_file) => { - let loc = db.lookup_intern_macro(macro_file.macro_call_id); - Some(loc.def.krate) - } - } - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] From cf4f7eb56660cfff355cb6bd41d5c17f7d19571b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 19:15:41 +0300 Subject: [PATCH 090/102] improve compile time a bit --- crates/ra_hir_def/src/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index ddabc7ca6687..04039376f394 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs @@ -292,7 +292,7 @@ fn expand_use_tree( prefix: Option, tree: ast::UseTree, hygiene: &Hygiene, - cb: &mut impl FnMut(Path, &ast::UseTree, bool, Option), + cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option), ) { if let Some(use_tree_list) = tree.use_tree_list() { let prefix = match tree.path() { From b441b4e8effeaf4532fd2e45c4d864480857c49e Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 13:36:37 -0400 Subject: [PATCH 091/102] Some clippy fixes --- crates/ra_assists/src/assists/early_return.rs | 2 +- crates/ra_assists/src/assists/inline_local_variable.rs | 6 ++---- crates/ra_assists/src/assists/raw_string.rs | 2 +- crates/ra_ide_api/src/call_info.rs | 2 +- crates/ra_ide_api/src/change.rs | 2 +- crates/ra_ide_api/src/completion/complete_path.rs | 2 +- crates/ra_ide_api/src/completion/presentation.rs | 4 ++-- crates/ra_ide_api/src/references/search_scope.rs | 5 ++--- crates/ra_ide_api/src/typing.rs | 2 +- crates/ra_lsp_server/src/main_loop.rs | 2 +- crates/ra_mbe/src/mbe_expander/matcher.rs | 3 +-- crates/ra_mbe/src/syntax_bridge.rs | 2 +- crates/ra_syntax/src/ast/make.rs | 4 ++-- xtask/src/codegen/gen_assists_docs.rs | 2 +- xtask/src/codegen/gen_parser_tests.rs | 8 +++----- xtask/src/main.rs | 2 +- xtask/tests/tidy-tests/docs.rs | 2 +- 17 files changed, 23 insertions(+), 29 deletions(-) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index e839d831e06f..ad6c5695a3a4 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -50,7 +50,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt } // check for early return and continue - let first_in_then_block = then_block.syntax().first_child()?.clone(); + let first_in_then_block = then_block.syntax().first_child()?; if ast::ReturnExpr::can_cast(first_in_then_block.kind()) || ast::ContinueExpr::can_cast(first_in_then_block.kind()) || first_in_then_block diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index f43910574897..a7fd9b6d2d6e 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs @@ -51,10 +51,8 @@ pub(crate) fn inline_local_varialbe(ctx: AssistCtx) -> Option< let mut wrap_in_parens = vec![true; refs.len()]; for (i, desc) in refs.iter().enumerate() { - let usage_node = ctx - .covering_node_for_range(desc.range) - .ancestors() - .find_map(|node| ast::PathExpr::cast(node))?; + let usage_node = + ctx.covering_node_for_range(desc.range).ancestors().find_map(ast::PathExpr::cast)?; let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); let usage_parent = match usage_parent_option { Some(u) => u, diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 6f4b66c3131a..58f7157ae21c 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs @@ -131,7 +131,7 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option { ctx.add_assist(AssistId("remove_hash"), "remove hash from raw string", |edit| { edit.target(token.text_range()); let result = &text[2..text.len() - 1]; - let result = if result.starts_with("\"") { + let result = if result.starts_with('\"') { // no more hash, escape let internal_str = &result[1..result.len() - 1]; format!("\"{}\"", internal_str.escape_default().to_string()) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 175af3fd9298..e494f56206dc 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -95,7 +95,7 @@ impl FnCallNode { Some(FnCallNode::CallExpr(expr)) } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) { Some(FnCallNode::MethodCallExpr(expr)) - } else if let Some(expr) = ast::MacroCall::cast(node.clone()) { + } else if let Some(expr) = ast::MacroCall::cast(node) { Some(FnCallNode::MacroCallExpr(expr)) } else { None diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 050249c0e680..39c5946c7f18 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs @@ -43,7 +43,7 @@ impl fmt::Debug for AnalysisChange { if !self.libraries_added.is_empty() { d.field("libraries_added", &self.libraries_added.len()); } - if !self.crate_graph.is_some() { + if !self.crate_graph.is_none() { d.field("crate_graph", &self.crate_graph); } d.finish() diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 956d8ce49c44..a58fdc036fef 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -67,7 +67,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { }); } } - _ => return, + _ => {} }; } diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index f7e98e6df2de..65bb639ed508 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -136,7 +136,7 @@ impl Completions { for (idx, s) in docs.match_indices(¯o_name) { let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); // Ensure to match the full word - if after.starts_with("!") + if after.starts_with('!') && before .chars() .rev() @@ -225,7 +225,7 @@ impl Completions { } else { (format!("{}($0)", data.name()), format!("{}(…)", name)) }; - builder = builder.lookup_by(name.clone()).label(label).insert_snippet(snippet); + builder = builder.lookup_by(name).label(label).insert_snippet(snippet); } self.add(builder) diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index dbd1af597693..f2789e0b2a43 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -111,8 +111,7 @@ impl NameDefinition { if vis.as_str() != "" { let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); - let mut res = - source_root.walk().map(|id| (id.into(), None)).collect::>(); + let mut res = source_root.walk().map(|id| (id, None)).collect::>(); // FIXME: add "pub(in path)" @@ -128,7 +127,7 @@ impl NameDefinition { let root_file = crate_graph.crate_root(crate_id); let source_root_id = db.file_source_root(root_file); let source_root = db.source_root(source_root_id); - res.extend(source_root.walk().map(|id| (id.into(), None))); + res.extend(source_root.walk().map(|id| (id, None))); } } return SearchScope::new(res); diff --git a/crates/ra_ide_api/src/typing.rs b/crates/ra_ide_api/src/typing.rs index 2dfbe6944dd9..d51132f73605 100644 --- a/crates/ra_ide_api/src/typing.rs +++ b/crates/ra_ide_api/src/typing.rs @@ -261,7 +261,7 @@ impl S { fn type_char(char_typed: char, before: &str, after: &str) { let (actual, file_change) = do_type_char(char_typed, before) - .expect(&format!("typing `{}` did nothing", char_typed)); + .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed)); if after.contains("<|>") { let (offset, after) = extract_offset(after); diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 1a87706fee3f..379dab4384f1 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -196,7 +196,7 @@ pub fn main_loop( task_receiver.into_iter().for_each(|task| { on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) }); - libdata_receiver.into_iter().for_each(|lib| drop(lib)); + libdata_receiver.into_iter().for_each(drop); log::info!("...tasks have finished"); log::info!("joining threadpool..."); drop(pool); diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 0548e8512e66..33b9d483d2e1 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs @@ -123,7 +123,6 @@ fn match_subtree( } None => bindings.push_optional(name), } - () } Op::Repeat { subtree, kind, separator } => { match_repeat(bindings, subtree, kind, separator, src)? @@ -159,7 +158,7 @@ impl<'a> TtIter<'a> { pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { let ident = self.expect_ident()?; // check if it start from "`" - if ident.text.chars().next() != Some('\'') { + if !ident.text.starts_with('\'') { return Err(()); } Ok(ident) diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 1b543c84b869..592fcf527bb3 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs @@ -383,7 +383,7 @@ mod tests { "#, ); let expansion = expand(&rules, "literals!(foo);"); - let tts = &[expansion.clone().into()]; + let tts = &[expansion.into()]; let buffer = tt::buffer::TokenBuffer::new(tts); let mut tt_src = SubtreeTokenSource::new(&buffer); let mut tokens = vec![]; diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 76dad91557d7..3d5f18bfae68 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -129,11 +129,11 @@ pub fn where_clause(preds: impl Iterator) -> ast::WhereCl } pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr { - return ast_from_text(&format!( + ast_from_text(&format!( "fn f() {{ if !{} {{\n {}\n}}\n}}", condition.syntax().text(), statement - )); + )) } fn ast_from_text(text: &str) -> N { diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs index 0c4cf21529da..05afda8f1118 100644 --- a/xtask/src/codegen/gen_assists_docs.rs +++ b/xtask/src/codegen/gen_assists_docs.rs @@ -53,7 +53,7 @@ fn collect_assists() -> Result> { let doc = take_until(lines.by_ref(), "```").trim().to_string(); assert!( - doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with("."), + doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.'), "\n\n{}: assist docs should be proper sentences, with capitalization and a full stop at the end.\n\n{}\n\n", id, doc, ); diff --git a/xtask/src/codegen/gen_parser_tests.rs b/xtask/src/codegen/gen_parser_tests.rs index db1e59daccc1..d0f0f683b817 100644 --- a/xtask/src/codegen/gen_parser_tests.rs +++ b/xtask/src/codegen/gen_parser_tests.rs @@ -102,12 +102,10 @@ fn tests_from_dir(dir: &Path) -> Result { for test in collect_tests(&text) { if test.ok { if let Some(old_test) = res.ok.insert(test.name.clone(), test) { - Err(format!("Duplicate test: {}", old_test.name))? - } - } else { - if let Some(old_test) = res.err.insert(test.name.clone(), test) { - Err(format!("Duplicate test: {}", old_test.name))? + return Err(format!("Duplicate test: {}", old_test.name).into()); } + } else if let Some(old_test) = res.err.insert(test.name.clone(), test) { + return Err(format!("Duplicate test: {}", old_test.name).into()); } } Ok(()) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 04dca402c198..4d20232ffdcc 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -60,7 +60,7 @@ fn main() -> Result<()> { matches.finish().or_else(handle_extra_flags)?; let opts = InstallOpt { client: if server { None } else { Some(ClientOpt::VsCode) }, - server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) }, + server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, }; install(opts)? } diff --git a/xtask/tests/tidy-tests/docs.rs b/xtask/tests/tidy-tests/docs.rs index b766aeff16de..6a629ce63e8f 100644 --- a/xtask/tests/tidy-tests/docs.rs +++ b/xtask/tests/tidy-tests/docs.rs @@ -29,7 +29,7 @@ fn is_exclude_file(d: &DirEntry) -> bool { } fn is_hidden(entry: &DirEntry) -> bool { - entry.file_name().to_str().map(|s| s.starts_with(".")).unwrap_or(false) + entry.file_name().to_str().map(|s| s.starts_with('.')).unwrap_or(false) } #[test] From e529c8e3e287b4f70fac0b078fe7ce45394f914c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 30 Oct 2019 20:49:04 +0300 Subject: [PATCH 092/102] echo cargo version during install --- xtask/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 04dca402c198..d88b7ef376d4 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -229,6 +229,7 @@ fn install_server(opts: ServerOpt) -> Result<()> { let mut old_rust = false; if let Ok(output) = run_with_output("cargo --version", ".") { if let Ok(stdout) = String::from_utf8(output.stdout) { + println!("{}", stdout); if !check_version(&stdout, REQUIRED_RUST_VERSION) { old_rust = true; } From 7ad55e976c3f88e92075379c8a4c1f413665b458 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 14:38:45 -0400 Subject: [PATCH 093/102] Document match_ast! --- crates/ra_syntax/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index c315ba552814..5dcb6a95a663 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -160,6 +160,20 @@ impl SourceFile { } } +/// Matches a `SyntaxNode` against an `ast` type. +/// +/// # Example: +/// +/// ```ignore +/// match_ast! { +/// match node { +/// ast::CallExpr(it) => { ... }, +/// ast::MethodCallExpr(it) => { ... }, +/// ast::MacroCall(it) => { ... }, +/// _ => None, +/// } +/// } +/// ``` #[macro_export] macro_rules! match_ast { (match $node:ident { From 4d17658940ec73554dfef799b22e8829ab5ad61a Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 14:39:05 -0400 Subject: [PATCH 094/102] Use match_ast! in FnCallNode::with_node --- crates/ra_ide_api/src/call_info.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index e494f56206dc..3572825b57a6 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -4,7 +4,7 @@ use ra_db::SourceDatabase; use ra_syntax::{ algo::ancestors_at_offset, ast::{self, ArgListOwner}, - AstNode, SyntaxNode, TextUnit, + match_ast, AstNode, SyntaxNode, TextUnit, }; use test_utils::tested_by; @@ -91,14 +91,13 @@ enum FnCallNode { impl FnCallNode { fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option { ancestors_at_offset(syntax, offset).find_map(|node| { - if let Some(expr) = ast::CallExpr::cast(node.clone()) { - Some(FnCallNode::CallExpr(expr)) - } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) { - Some(FnCallNode::MethodCallExpr(expr)) - } else if let Some(expr) = ast::MacroCall::cast(node) { - Some(FnCallNode::MacroCallExpr(expr)) - } else { - None + match_ast! { + match node { + ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, + ast::MethodCallExpr(it) => { Some(FnCallNode::MethodCallExpr(it)) }, + ast::MacroCall(it) => { Some(FnCallNode::MacroCallExpr(it)) }, + _ => { None }, + } } }) } From b205a0ced3f8b2136ac256d8a3dca9fa09e910be Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 16:08:27 -0400 Subject: [PATCH 095/102] source_binder => match_ast! --- crates/ra_hir/src/source_binder.rs | 64 +++++++++++++++++------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 01f51ba5d470..152bc71bd287 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -12,7 +12,7 @@ use hir_expand::name::AsName; use ra_db::FileId; use ra_syntax::{ ast::{self, AstNode}, - AstPtr, + match_ast, AstPtr, SyntaxKind::*, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, }; @@ -37,24 +37,34 @@ fn try_get_resolver_for_node( file_id: FileId, node: &SyntaxNode, ) -> Option { - if let Some(module) = ast::Module::cast(node.clone()) { - let src = crate::Source { file_id: file_id.into(), ast: module }; - Some(crate::Module::from_declaration(db, src)?.resolver(db)) - } else if let Some(file) = ast::SourceFile::cast(node.clone()) { - let src = - crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(file) }; - Some(crate::Module::from_definition(db, src)?.resolver(db)) - } else if let Some(s) = ast::StructDef::cast(node.clone()) { - let src = crate::Source { file_id: file_id.into(), ast: s }; - Some(Struct::from_source(db, src)?.resolver(db)) - } else if let Some(e) = ast::EnumDef::cast(node.clone()) { - let src = crate::Source { file_id: file_id.into(), ast: e }; - Some(Enum::from_source(db, src)?.resolver(db)) - } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { - Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) - } else { - // FIXME add missing cases - None + match_ast! { + match node { + ast::Module(it) => { + let src = crate::Source { file_id: file_id.into(), ast: it }; + Some(crate::Module::from_declaration(db, src)?.resolver(db)) + }, + ast::SourceFile(it) => { + let src = + crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(it) }; + Some(crate::Module::from_definition(db, src)?.resolver(db)) + }, + ast::StructDef(it) => { + let src = crate::Source { file_id: file_id.into(), ast: it }; + Some(Struct::from_source(db, src)?.resolver(db)) + }, + ast::EnumDef(it) => { + let src = crate::Source { file_id: file_id.into(), ast: it }; + Some(Enum::from_source(db, src)?.resolver(db)) + }, + _ => { + if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { + Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) + } else { + // FIXME add missing cases + None + } + }, + } } } @@ -68,16 +78,14 @@ fn def_with_body_from_child_node( let ctx = LocationCtx::new(db, module.id, file_id.into()); node.ancestors().find_map(|node| { - if let Some(def) = ast::FnDef::cast(node.clone()) { - return Some(Function { id: ctx.to_def(&def) }.into()); + match_ast! { + match node { + ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) }, + ast::ConstDef(def) => { Some(Const { id: ctx.to_def(&def) }.into()) }, + ast::StaticDef(def) => { Some(Static { id: ctx.to_def(&def) }.into()) }, + _ => { None }, + } } - if let Some(def) = ast::ConstDef::cast(node.clone()) { - return Some(Const { id: ctx.to_def(&def) }.into()); - } - if let Some(def) = ast::StaticDef::cast(node) { - return Some(Static { id: ctx.to_def(&def) }.into()); - } - None }) } From 78f93c8033d4803167536a070c2162b072e16055 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 16:08:59 -0400 Subject: [PATCH 096/102] traits => match_ast! --- crates/ra_syntax/src/ast/traits.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 76313684eaba..c2b005886a97 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use crate::{ ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, + match_ast, syntax_node::{SyntaxElementChildren, SyntaxNodeChildren}, }; @@ -68,11 +69,12 @@ impl Iterator for ItemOrMacroIter { fn next(&mut self) -> Option { loop { let n = self.0.next()?; - if let Some(item) = ast::ModuleItem::cast(n.clone()) { - return Some(ItemOrMacro::Item(item)); - } - if let Some(call) = ast::MacroCall::cast(n) { - return Some(ItemOrMacro::Macro(call)); + match_ast! { + match n { + ast::ModuleItem(it) => { return Some(ItemOrMacro::Item(it)) }, + ast::MacroCall(it) => { return Some(ItemOrMacro::Macro(it)) }, + _ => {}, + } } } } From 4ad37df22339ff91779782d37ab315ef0ce274eb Mon Sep 17 00:00:00 2001 From: kjeremy Date: Wed, 30 Oct 2019 16:09:16 -0400 Subject: [PATCH 097/102] runnables => match_ast! --- crates/ra_ide_api/src/runnables.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs index 910883da7442..1b5c8deea0f8 100644 --- a/crates/ra_ide_api/src/runnables.rs +++ b/crates/ra_ide_api/src/runnables.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use ra_db::SourceDatabase; use ra_syntax::{ ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, - SyntaxNode, TextRange, + match_ast, SyntaxNode, TextRange, }; use crate::{db::RootDatabase, FileId}; @@ -29,12 +29,12 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { } fn runnable(db: &RootDatabase, file_id: FileId, item: SyntaxNode) -> Option { - if let Some(fn_def) = ast::FnDef::cast(item.clone()) { - runnable_fn(fn_def) - } else if let Some(m) = ast::Module::cast(item) { - runnable_mod(db, file_id, m) - } else { - None + match_ast! { + match item { + ast::FnDef(it) => { runnable_fn(it) }, + ast::Module(it) => { runnable_mod(db, file_id, it) }, + _ => { None }, + } } } From 462c1b49c652b1fb271e6243f3feee13e4ea8880 Mon Sep 17 00:00:00 2001 From: krk Date: Wed, 30 Oct 2019 21:17:27 +0100 Subject: [PATCH 098/102] Fix typo in xtask/src/main.rs. --- xtask/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index abcbf7129b57..e04e45f15752 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -2,7 +2,7 @@ //! //! This binary defines various auxiliary build commands, which are not //! expressible with just `cargo`. Notably, it provides `cargo xtask codegen` -//! for code genetaiont and `cargo xtask install` for installation of +//! for code generation and `cargo xtask install` for installation of //! rust-analyzer server and client. //! //! This binary is integrated into the `cargo` command line by using an alias in From 9bbb27604d12b97506da6ee3fed95c66d696a6ac Mon Sep 17 00:00:00 2001 From: krk Date: Wed, 30 Oct 2019 21:44:06 +0100 Subject: [PATCH 099/102] Add link to the vscode VIM extension compatibility warning. --- editors/code/src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts index 39fe6efd8890..c06928d122ba 100644 --- a/editors/code/src/extension.ts +++ b/editors/code/src/extension.ts @@ -45,7 +45,7 @@ export function activate(context: vscode.ExtensionContext) { }); } catch (_) { vscode.window.showWarningMessage( - 'Enhanced typing feature is disabled because of incompatibility with VIM extension' + 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings' ); } } From 6f4d5f7339395d854e4ba2af227de851246e528f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 31 Oct 2019 10:31:29 +0300 Subject: [PATCH 100/102] move mod_resolution to hir_def --- crates/ra_hir/src/nameres.rs | 1 - crates/ra_hir/src/nameres/collector.rs | 9 ++++++--- crates/ra_hir_def/src/nameres.rs | 2 ++ .../src/nameres/mod_resolution.rs | 17 +++++++---------- 4 files changed, 15 insertions(+), 14 deletions(-) rename crates/{ra_hir => ra_hir_def}/src/nameres/mod_resolution.rs (88%) diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 39f585b446a9..7c4d07de0da3 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -49,7 +49,6 @@ mod per_ns; mod collector; -mod mod_resolution; #[cfg(test)] mod tests; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index e2e13805acc0..ee0a4c99fe00 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -1,6 +1,9 @@ //! FIXME: write short doc here -use hir_def::{attr::Attr, nameres::raw}; +use hir_def::{ + attr::Attr, + nameres::{mod_resolution::ModDir, raw}, +}; use hir_expand::name; use ra_cfg::CfgOptions; use ra_db::FileId; @@ -12,8 +15,8 @@ use crate::{ db::DefDatabase, ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, nameres::{ - diagnostics::DefDiagnostic, mod_resolution::ModDir, Crate, CrateDefMap, CrateModuleId, - ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, + diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, + PerNs, ReachedFixedPoint, Resolution, ResolveMode, }, Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, Struct, Trait, TypeAlias, Union, diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 5893708e8ba0..11ba8a7770d9 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -1,3 +1,5 @@ //! FIXME: write short doc here +// FIXME: review privacy of submodules pub mod raw; +pub mod mod_resolution; diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs similarity index 88% rename from crates/ra_hir/src/nameres/mod_resolution.rs rename to crates/ra_hir_def/src/nameres/mod_resolution.rs index 334cdd692ac2..7d7e2779aa20 100644 --- a/crates/ra_hir/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs @@ -1,12 +1,13 @@ //! This module resolves `mod foo;` declaration to file. +use hir_expand::name::Name; use ra_db::FileId; use ra_syntax::SmolStr; use relative_path::RelativePathBuf; -use crate::{db::DefDatabase, HirFileId, Name}; +use crate::{db::DefDatabase2, HirFileId}; #[derive(Clone, Debug)] -pub(super) struct ModDir { +pub struct ModDir { /// `.` for `mod.rs`, `lib.rs` /// `./foo` for `foo.rs` /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` @@ -16,15 +17,11 @@ pub(super) struct ModDir { } impl ModDir { - pub(super) fn root() -> ModDir { + pub fn root() -> ModDir { ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } } - pub(super) fn descend_into_definition( - &self, - name: &Name, - attr_path: Option<&SmolStr>, - ) -> ModDir { + pub fn descend_into_definition(&self, name: &Name, attr_path: Option<&SmolStr>) -> ModDir { let mut path = self.path.clone(); match attr_to_path(attr_path) { None => path.push(&name.to_string()), @@ -38,9 +35,9 @@ impl ModDir { ModDir { path, root_non_dir_owner: false } } - pub(super) fn resolve_declaration( + pub fn resolve_declaration( &self, - db: &impl DefDatabase, + db: &impl DefDatabase2, file_id: HirFileId, name: &Name, attr_path: Option<&SmolStr>, From b20d37cb49536e19f6af57b00258f86eb8f19325 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 31 Oct 2019 10:51:54 +0300 Subject: [PATCH 101/102] move builtin types to hir_def --- crates/ra_hir/src/code_model.rs | 48 ++------------------ crates/ra_hir/src/lib.rs | 7 +-- crates/ra_hir/src/nameres.rs | 5 +-- crates/ra_hir/src/resolve.rs | 4 +- crates/ra_hir/src/ty/lower.rs | 16 ++++--- crates/ra_hir/src/ty/primitive.rs | 22 +--------- crates/ra_hir_def/src/builtin_type.rs | 63 +++++++++++++++++++++++++++ crates/ra_hir_def/src/lib.rs | 1 + 8 files changed, 88 insertions(+), 78 deletions(-) create mode 100644 crates/ra_hir_def/src/builtin_type.rs diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index a6ce23dd10e4..e0c6d634029c 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -6,13 +6,11 @@ pub(crate) mod docs; use std::sync::Arc; use hir_def::{ + builtin_type::BuiltinType, type_ref::{Mutability, TypeRef}, CrateModuleId, ModuleId, }; -use hir_expand::name::{ - self, AsName, BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, - U32, U64, U8, USIZE, -}; +use hir_expand::name::{self, AsName}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; @@ -30,10 +28,7 @@ use crate::{ nameres::{ImportId, ModuleScope, Namespace}, resolve::{Resolver, Scope, TypeNs}, traits::TraitData, - ty::{ - primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, - InferenceResult, TraitRef, - }, + ty::{InferenceResult, TraitRef}, Either, HasSource, Name, Ty, }; @@ -87,41 +82,6 @@ pub struct Module { pub(crate) id: ModuleId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum BuiltinType { - Char, - Bool, - Str, - Int(IntTy), - Float(FloatTy), -} - -impl BuiltinType { - #[rustfmt::skip] - pub(crate) const ALL: &'static [(Name, BuiltinType)] = &[ - (CHAR, BuiltinType::Char), - (BOOL, BuiltinType::Bool), - (STR, BuiltinType::Str), - - (ISIZE, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::Xsize })), - (I8, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X8 })), - (I16, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X16 })), - (I32, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X32 })), - (I64, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X64 })), - (I128, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X128 })), - - (USIZE, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize })), - (U8, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X8 })), - (U16, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X16 })), - (U32, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X32 })), - (U64, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X64 })), - (U128, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X128 })), - - (F32, BuiltinType::Float(FloatTy { bitness: FloatBitness::X32 })), - (F64, BuiltinType::Float(FloatTy { bitness: FloatBitness::X64 })), - ]; -} - /// The defs which can be visible in the module. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ModuleDef { @@ -625,7 +585,7 @@ impl FnData { let self_type = if let Some(type_ref) = self_param.ascribed_type() { TypeRef::from_ast(type_ref) } else { - let self_type = TypeRef::Path(SELF_TYPE.into()); + let self_type = TypeRef::Path(name::SELF_TYPE.into()); match self_param.kind() { ast::SelfParamKind::Owned => self_type, ast::SelfParamKind::Ref => { diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 603b0c3dc3f1..40f5562b406a 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -63,9 +63,9 @@ pub use crate::{ code_model::{ docs::{DocDef, Docs, Documentation}, src::{HasBodySource, HasSource, Source}, - Adt, AssocItem, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, - DefWithBody, Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, - ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, + Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, + EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, + ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }, expr::ExprScopes, from_source::FromSource, @@ -81,6 +81,7 @@ pub use crate::{ }; pub use hir_def::{ + builtin_type::BuiltinType, path::{Path, PathKind}, type_ref::Mutability, }; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7c4d07de0da3..7ba03182718c 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -54,7 +54,7 @@ mod tests; use std::sync::Arc; -use hir_def::CrateModuleId; +use hir_def::{builtin_type::BuiltinType, CrateModuleId}; use once_cell::sync::Lazy; use ra_arena::Arena; use ra_db::{Edition, FileId}; @@ -68,8 +68,7 @@ use crate::{ diagnostics::DiagnosticSink, ids::MacroDefId, nameres::diagnostics::DefDiagnostic, - Adt, AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, - Trait, + Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, }; pub use self::per_ns::{Namespace, PerNs}; diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index f77c9df9f023..75b24d386f16 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use hir_def::{ + builtin_type::BuiltinType, path::{Path, PathKind}, CrateModuleId, }; @@ -18,8 +19,7 @@ use crate::{ generics::GenericParams, impl_block::ImplBlock, nameres::{CrateDefMap, PerNs}, - Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, - Trait, TypeAlias, + Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, }; #[derive(Debug, Clone, Default)] diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 0f49a0e541df..dd7cd979ff47 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -9,6 +9,7 @@ use std::iter; use std::sync::Arc; use hir_def::{ + builtin_type::BuiltinType, path::{GenericArg, PathSegment}, type_ref::{TypeBound, TypeRef}, }; @@ -24,10 +25,13 @@ use crate::{ generics::{GenericDef, WherePredicate}, nameres::Namespace, resolve::{Resolver, TypeNs}, - ty::Adt, + ty::{ + primitive::{FloatTy, IntTy}, + Adt, + }, util::make_mut_slice, - BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, - Trait, TypeAlias, Union, + Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, + TypeAlias, Union, }; impl Ty { @@ -643,8 +647,10 @@ fn type_for_builtin(def: BuiltinType) -> Ty { BuiltinType::Char => TypeCtor::Char, BuiltinType::Bool => TypeCtor::Bool, BuiltinType::Str => TypeCtor::Str, - BuiltinType::Int(ty) => TypeCtor::Int(ty.into()), - BuiltinType::Float(ty) => TypeCtor::Float(ty.into()), + BuiltinType::Int { signedness, bitness } => { + TypeCtor::Int(IntTy { signedness, bitness }.into()) + } + BuiltinType::Float { bitness } => TypeCtor::Float(FloatTy { bitness }.into()), }) } diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 8966f9d1d502..1749752f10e9 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs @@ -2,27 +2,7 @@ use std::fmt; -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Signedness { - Signed, - Unsigned, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum IntBitness { - Xsize, - X8, - X16, - X32, - X64, - X128, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum FloatBitness { - X32, - X64, -} +pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum UncertainIntTy { diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs new file mode 100644 index 000000000000..12929caa9003 --- /dev/null +++ b/crates/ra_hir_def/src/builtin_type.rs @@ -0,0 +1,63 @@ +//! This module defines built-in types. +//! +//! A peculiarity of built-in types is that they are always available and are +//! not associated with any particular crate. + +use hir_expand::name::{self, Name}; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Signedness { + Signed, + Unsigned, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum IntBitness { + Xsize, + X8, + X16, + X32, + X64, + X128, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum FloatBitness { + X32, + X64, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum BuiltinType { + Char, + Bool, + Str, + Int { signedness: Signedness, bitness: IntBitness }, + Float { bitness: FloatBitness }, +} + +impl BuiltinType { + #[rustfmt::skip] + pub const ALL: &'static [(Name, BuiltinType)] = &[ + (name::CHAR, BuiltinType::Char), + (name::BOOL, BuiltinType::Bool), + (name::STR, BuiltinType::Str ), + + (name::ISIZE, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::Xsize }), + (name::I8, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X8 }), + (name::I16, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X16 }), + (name::I32, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X32 }), + (name::I64, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X64 }), + (name::I128, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X128 }), + + (name::USIZE, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }), + (name::U8, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }), + (name::U16, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }), + (name::U32, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }), + (name::U64, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }), + (name::U128, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }), + + (name::F32, BuiltinType::Float { bitness: FloatBitness::X32 }), + (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }), + ]; +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 7a6c7b30125e..8cbff673cf71 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -11,6 +11,7 @@ pub mod db; pub mod attr; pub mod path; pub mod type_ref; +pub mod builtin_type; // FIXME: this should be private pub mod nameres; From 1602db7d7d6aa38b4ee50de8cbe734529853d615 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 31 Oct 2019 11:23:30 +0300 Subject: [PATCH 102/102] add ModuleDefId to hir_def --- crates/ra_hir/src/adt.rs | 8 ++--- crates/ra_hir/src/code_model.rs | 6 ++-- crates/ra_hir_def/src/lib.rs | 58 +++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index 97424b39e00d..4fa2062bdba1 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,7 +3,7 @@ use std::sync::Arc; -use hir_def::type_ref::TypeRef; +use hir_def::{type_ref::TypeRef, LocalEnumVariantId}; use hir_expand::name::AsName; use ra_arena::{impl_arena_id, Arena, RawId}; use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; @@ -68,7 +68,7 @@ impl EnumVariant { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumData { pub(crate) name: Option, - pub(crate) variants: Arena, + pub(crate) variants: Arena, } impl EnumData { @@ -85,10 +85,6 @@ impl EnumData { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct EnumVariantId(RawId); -impl_arena_id!(EnumVariantId); - #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct EnumVariantData { pub(crate) name: Option, diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e0c6d634029c..b32aa145ea8b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -8,14 +8,14 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, type_ref::{Mutability, TypeRef}, - CrateModuleId, ModuleId, + CrateModuleId, LocalEnumVariantId, ModuleId, }; use hir_expand::name::{self, AsName}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ - adt::{EnumVariantId, StructFieldId, VariantDef}, + adt::{StructFieldId, VariantDef}, db::{AstDatabase, DefDatabase, HirDatabase}, diagnostics::DiagnosticSink, expr::{validation::ExprValidator, Body, BodySourceMap}, @@ -410,7 +410,7 @@ impl Enum { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariant { pub(crate) parent: Enum, - pub(crate) id: EnumVariantId, + pub(crate) id: LocalEnumVariantId, } impl EnumVariant { diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 8cbff673cf71..93ad40005c7f 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -23,7 +23,7 @@ use ra_arena::{impl_arena_id, RawId}; use ra_db::{salsa, CrateId, FileId}; use ra_syntax::{ast, AstNode, SyntaxNode}; -use crate::db::InternDatabase; +use crate::{builtin_type::BuiltinType, db::InternDatabase}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Source { @@ -256,7 +256,7 @@ pub struct EnumVariantId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) struct LocalEnumVariantId(RawId); +pub struct LocalEnumVariantId(RawId); impl_arena_id!(LocalEnumVariantId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -306,3 +306,57 @@ impl AstItemDef for TypeAliasId { db.lookup_intern_type_alias(self) } } + +macro_rules! impl_froms { + ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { + $( + impl From<$v> for $e { + fn from(it: $v) -> $e { + $e::$v(it) + } + } + $($( + impl From<$sv> for $e { + fn from(it: $sv) -> $e { + $e::$v($v::$sv(it)) + } + } + )*)? + )* + } +} + +/// A Data Type +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum AdtId { + StructId(StructId), + UnionId(UnionId), + EnumId(EnumId), +} +impl_froms!(AdtId: StructId, UnionId, EnumId); + +/// The defs which can be visible in the module. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ModuleDefId { + ModuleId(ModuleId), + FunctionId(FunctionId), + AdtId(AdtId), + // Can't be directly declared, but can be imported. + EnumVariantId(EnumVariantId), + ConstId(ConstId), + StaticId(StaticId), + TraitId(TraitId), + TypeAliasId(TypeAliasId), + BuiltinType(BuiltinType), +} +impl_froms!( + ModuleDefId: ModuleId, + FunctionId, + AdtId(StructId, EnumId, UnionId), + EnumVariantId, + ConstId, + StaticId, + TraitId, + TypeAliasId, + BuiltinType +);