aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml12
-rw-r--r--crates/ra_cargo_watch/src/conv.rs14
-rw-r--r--crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap52
-rw-r--r--crates/ra_cargo_watch/src/lib.rs67
-rw-r--r--crates/ra_hir/src/code_model.rs20
-rw-r--r--crates/ra_hir/src/lib.rs12
-rw-r--r--crates/ra_hir/src/semantics.rs29
-rw-r--r--crates/ra_hir/src/source_analyzer.rs12
-rw-r--r--crates/ra_ide/src/references.rs32
-rw-r--r--crates/ra_ide/src/references/rename.rs57
-rw-r--r--crates/ra_ide_db/src/search.rs20
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs27
-rw-r--r--xtask/src/dist.rs11
-rw-r--r--xtask/src/main.rs14
14 files changed, 252 insertions, 127 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index df34dfdb8..c055d113d 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -49,12 +49,16 @@ jobs:
49 node-version: 12.x 49 node-version: 12.x
50 50
51 - name: Dist 51 - name: Dist
52 if: github.ref == 'refs/heads/release' 52 if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/release'
53 run: cargo xtask dist --version 0.2.$GITHUB_RUN_NUMBER --tag $(date --iso --utc) 53 run: cargo xtask dist --client --version 0.2.$GITHUB_RUN_NUMBER --tag $(date --iso --utc)
54 54
55 - name: Dist 55 - name: Dist
56 if: github.ref != 'refs/heads/release' 56 if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release'
57 run: cargo xtask dist --version 0.3.$GITHUB_RUN_NUMBER-nightly --tag nightly 57 run: cargo xtask dist --client --version 0.3.$GITHUB_RUN_NUMBER-nightly --tag nightly
58
59 - name: Dist
60 if: matrix.os != 'ubuntu-latest'
61 run: cargo xtask dist
58 62
59 - name: Upload artifacts 63 - name: Upload artifacts
60 uses: actions/upload-artifact@v1 64 uses: actions/upload-artifact@v1
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index c6f8ca329..817543deb 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_cargo_watch/src/conv.rs
@@ -1,7 +1,8 @@
1//! This module provides the functionality needed to convert diagnostics from 1//! This module provides the functionality needed to convert diagnostics from
2//! `cargo check` json format to the LSP diagnostic format. 2//! `cargo check` json format to the LSP diagnostic format.
3use cargo_metadata::diagnostic::{ 3use cargo_metadata::diagnostic::{
4 Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion, 4 Applicability, Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan,
5 DiagnosticSpanMacroExpansion,
5}; 6};
6use lsp_types::{ 7use lsp_types::{
7 CodeAction, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, 8 CodeAction, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag,
@@ -136,10 +137,13 @@ fn map_rust_child_diagnostic(
136 137
137 let mut edit_map: HashMap<Url, Vec<TextEdit>> = HashMap::new(); 138 let mut edit_map: HashMap<Url, Vec<TextEdit>> = HashMap::new();
138 for &span in &spans { 139 for &span in &spans {
139 if let Some(suggested_replacement) = &span.suggested_replacement { 140 match (&span.suggestion_applicability, &span.suggested_replacement) {
140 let location = map_span_to_location(span, workspace_root); 141 (Some(Applicability::MachineApplicable), Some(suggested_replacement)) => {
141 let edit = TextEdit::new(location.range, suggested_replacement.clone()); 142 let location = map_span_to_location(span, workspace_root);
142 edit_map.entry(location.uri).or_default().push(edit); 143 let edit = TextEdit::new(location.range, suggested_replacement.clone());
144 edit_map.entry(location.uri).or_default().push(edit);
145 }
146 _ => {}
143 } 147 }
144 } 148 }
145 149
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
index 9e8f4eff4..a59fa84fa 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
+++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
@@ -58,44 +58,26 @@ expression: diag
58 }, 58 },
59 message: "lint level defined here", 59 message: "lint level defined here",
60 }, 60 },
61 DiagnosticRelatedInformation {
62 location: Location {
63 uri: "file:///test/compiler/mir/tagset.rs",
64 range: Range {
65 start: Position {
66 line: 41,
67 character: 23,
68 },
69 end: Position {
70 line: 41,
71 character: 28,
72 },
73 },
74 },
75 message: "consider passing by value instead",
76 },
61 ], 77 ],
62 ), 78 ),
63 tags: None, 79 tags: None,
64 }, 80 },
65 fixes: [ 81 fixes: [],
66 CodeAction {
67 title: "consider passing by value instead",
68 kind: Some(
69 "quickfix",
70 ),
71 diagnostics: None,
72 edit: Some(
73 WorkspaceEdit {
74 changes: Some(
75 {
76 "file:///test/compiler/mir/tagset.rs": [
77 TextEdit {
78 range: Range {
79 start: Position {
80 line: 41,
81 character: 23,
82 },
83 end: Position {
84 line: 41,
85 character: 28,
86 },
87 },
88 new_text: "self",
89 },
90 ],
91 },
92 ),
93 document_changes: None,
94 },
95 ),
96 command: None,
97 is_preferred: None,
98 },
99 ],
100 }, 82 },
101] 83]
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index bffe5eb00..7c525c430 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -8,9 +8,10 @@ use lsp_types::{
8 WorkDoneProgressEnd, WorkDoneProgressReport, 8 WorkDoneProgressEnd, WorkDoneProgressReport,
9}; 9};
10use std::{ 10use std::{
11 error, fmt,
11 io::{BufRead, BufReader}, 12 io::{BufRead, BufReader},
12 path::{Path, PathBuf}, 13 path::{Path, PathBuf},
13 process::{Child, Command, Stdio}, 14 process::{Command, Stdio},
14 thread::JoinHandle, 15 thread::JoinHandle,
15 time::Instant, 16 time::Instant,
16}; 17};
@@ -70,10 +71,10 @@ impl std::ops::Drop for CheckWatcher {
70 fn drop(&mut self) { 71 fn drop(&mut self) {
71 if let Some(handle) = self.handle.take() { 72 if let Some(handle) = self.handle.take() {
72 // Take the sender out of the option 73 // Take the sender out of the option
73 let recv = self.cmd_send.take(); 74 let cmd_send = self.cmd_send.take();
74 75
75 // Dropping the sender finishes the thread loop 76 // Dropping the sender finishes the thread loop
76 drop(recv); 77 drop(cmd_send);
77 78
78 // Join the thread, it should finish shortly. We don't really care 79 // Join the thread, it should finish shortly. We don't really care
79 // whether it panicked, so it is safe to ignore the result 80 // whether it panicked, so it is safe to ignore the result
@@ -246,11 +247,21 @@ enum CheckEvent {
246 End, 247 End,
247} 248}
248 249
250#[derive(Debug)]
251pub struct CargoError(String);
252
253impl fmt::Display for CargoError {
254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255 write!(f, "Cargo failed: {}", self.0)
256 }
257}
258impl error::Error for CargoError {}
259
249pub fn run_cargo( 260pub fn run_cargo(
250 args: &[String], 261 args: &[String],
251 current_dir: Option<&Path>, 262 current_dir: Option<&Path>,
252 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, 263 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
253) -> Child { 264) -> Result<(), CargoError> {
254 let mut command = Command::new("cargo"); 265 let mut command = Command::new("cargo");
255 if let Some(current_dir) = current_dir { 266 if let Some(current_dir) = current_dir {
256 command.current_dir(current_dir); 267 command.current_dir(current_dir);
@@ -273,6 +284,8 @@ pub fn run_cargo(
273 // simply skip a line if it doesn't parse, which just ignores any 284 // simply skip a line if it doesn't parse, which just ignores any
274 // erroneus output. 285 // erroneus output.
275 let stdout = BufReader::new(child.stdout.take().unwrap()); 286 let stdout = BufReader::new(child.stdout.take().unwrap());
287 let mut read_at_least_one_message = false;
288
276 for line in stdout.lines() { 289 for line in stdout.lines() {
277 let line = match line { 290 let line = match line {
278 Ok(line) => line, 291 Ok(line) => line,
@@ -291,12 +304,31 @@ pub fn run_cargo(
291 } 304 }
292 }; 305 };
293 306
307 read_at_least_one_message = true;
308
294 if !on_message(message) { 309 if !on_message(message) {
295 break; 310 break;
296 } 311 }
297 } 312 }
298 313
299 child 314 // It is okay to ignore the result, as it only errors if the process is already dead
315 let _ = child.kill();
316
317 let err_msg = match child.wait() {
318 Ok(exit_code) if !exit_code.success() && !read_at_least_one_message => {
319 // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
320 // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
321 format!(
322 "the command produced no valid metadata (exit code: {:?}): cargo {}",
323 exit_code,
324 args.join(" ")
325 )
326 }
327 Err(err) => format!("io error: {:?}", err),
328 Ok(_) => return Ok(()),
329 };
330
331 Err(CargoError(err_msg))
300} 332}
301 333
302impl WatchThread { 334impl WatchThread {
@@ -325,7 +357,7 @@ impl WatchThread {
325 // which will break out of the loop, and continue the shutdown 357 // which will break out of the loop, and continue the shutdown
326 let _ = message_send.send(CheckEvent::Begin); 358 let _ = message_send.send(CheckEvent::Begin);
327 359
328 let mut child = run_cargo(&args, Some(&workspace_root), &mut |message| { 360 let res = run_cargo(&args, Some(&workspace_root), &mut |message| {
329 // Skip certain kinds of messages to only spend time on what's useful 361 // Skip certain kinds of messages to only spend time on what's useful
330 match &message { 362 match &message {
331 Message::CompilerArtifact(artifact) if artifact.fresh => return true, 363 Message::CompilerArtifact(artifact) if artifact.fresh => return true,
@@ -334,26 +366,19 @@ impl WatchThread {
334 _ => {} 366 _ => {}
335 } 367 }
336 368
337 match message_send.send(CheckEvent::Msg(message)) { 369 // if the send channel was closed, we want to shutdown
338 Ok(()) => {} 370 message_send.send(CheckEvent::Msg(message)).is_ok()
339 Err(_err) => {
340 // The send channel was closed, so we want to shutdown
341 return false;
342 }
343 };
344
345 true
346 }); 371 });
347 372
373 if let Err(err) = res {
374 // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
375 // to display user-caused misconfiguration errors instead of just logging them here
376 log::error!("Cargo watcher failed {:?}", err);
377 }
378
348 // We can ignore any error here, as we are already in the progress 379 // We can ignore any error here, as we are already in the progress
349 // of shutting down. 380 // of shutting down.
350 let _ = message_send.send(CheckEvent::End); 381 let _ = message_send.send(CheckEvent::End);
351
352 // It is okay to ignore the result, as it only errors if the process is already dead
353 let _ = child.kill();
354
355 // Again, we don't care about the exit status so just ignore the result
356 let _ = child.wait();
357 })) 382 }))
358 } else { 383 } else {
359 None 384 None
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 4b150ef06..e91abf6f5 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 docs::Documentation, 10 docs::Documentation,
11 expr::{BindingAnnotation, Pat, PatId}, 11 expr::{BindingAnnotation, Pat, PatId},
12 per_ns::PerNs, 12 per_ns::PerNs,
13 resolver::HasResolver, 13 resolver::{HasResolver, Resolver},
14 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
15 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, 15 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
16 ImplId, LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, 16 ImplId, LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId,
@@ -912,10 +912,8 @@ impl Local {
912 let def = DefWithBodyId::from(self.parent); 912 let def = DefWithBodyId::from(self.parent);
913 let infer = db.infer(def); 913 let infer = db.infer(def);
914 let ty = infer[self.pat_id].clone(); 914 let ty = infer[self.pat_id].clone();
915 let resolver = def.resolver(db.upcast());
916 let krate = def.module(db.upcast()).krate; 915 let krate = def.module(db.upcast()).krate;
917 let environment = TraitEnvironment::lower(db, &resolver); 916 Type::new(db, krate, def, ty)
918 Type { krate, ty: InEnvironment { value: ty, environment } }
919 } 917 }
920 918
921 pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::BindPat, ast::SelfParam>> { 919 pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::BindPat, ast::SelfParam>> {
@@ -1020,11 +1018,21 @@ impl ImplDef {
1020 1018
1021#[derive(Clone, PartialEq, Eq, Debug)] 1019#[derive(Clone, PartialEq, Eq, Debug)]
1022pub struct Type { 1020pub struct Type {
1023 pub(crate) krate: CrateId, 1021 krate: CrateId,
1024 pub(crate) ty: InEnvironment<Ty>, 1022 ty: InEnvironment<Ty>,
1025} 1023}
1026 1024
1027impl Type { 1025impl Type {
1026 pub(crate) fn new_with_resolver(
1027 db: &dyn HirDatabase,
1028 resolver: &Resolver,
1029 ty: Ty,
1030 ) -> Option<Type> {
1031 let krate = resolver.krate()?;
1032 let environment = TraitEnvironment::lower(db, &resolver);
1033 Some(Type { krate, ty: InEnvironment { value: ty, environment } })
1034 }
1035
1028 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { 1036 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1029 let resolver = lexical_env.resolver(db.upcast()); 1037 let resolver = lexical_env.resolver(db.upcast());
1030 let environment = TraitEnvironment::lower(db, &resolver); 1038 let environment = TraitEnvironment::lower(db, &resolver);
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 9f59d590c..713d45f48 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -4,6 +4,18 @@
4//! The principal difference between HIR and syntax trees is that HIR is bound 4//! The principal difference between HIR and syntax trees is that HIR is bound
5//! to a particular crate instance. That is, it has cfg flags and features 5//! to a particular crate instance. That is, it has cfg flags and features
6//! applied. So, the relation between syntax and HIR is many-to-one. 6//! applied. So, the relation between syntax and HIR is many-to-one.
7//!
8//! HIR is the public API of the all of the compiler logic above syntax trees.
9//! It is written in "OO" style. Each type is self contained (as in, it knows it's
10//! parents and full context). It should be "clean code".
11//!
12//! `ra_hir_*` crates are the implementation of the compiler logic.
13//! They are written in "ECS" style, with relatively little abstractions.
14//! Many types are not self-contained, and explicitly use local indexes, arenas, etc.
15//!
16//! `ra_hir` is what insulates the "we don't know how to actually write an incremental compiler"
17//! from the ide with completions, hovers, etc. It is a (soft, internal) boundary:
18//! https://www.tedinski.com/2018/02/06/system-boundaries.html.
7 19
8#![recursion_limit = "512"] 20#![recursion_limit = "512"]
9 21
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 55e634528..d982f6ffa 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -12,7 +12,8 @@ use hir_expand::ExpansionInfo;
12use ra_db::{FileId, FileRange}; 12use ra_db::{FileId, FileRange};
13use ra_prof::profile; 13use ra_prof::profile;
14use ra_syntax::{ 14use ra_syntax::{
15 algo::skip_trivia_token, ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit, 15 algo::{find_node_at_offset, skip_trivia_token},
16 ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit,
16}; 17};
17use rustc_hash::{FxHashMap, FxHashSet}; 18use rustc_hash::{FxHashMap, FxHashSet};
18 19
@@ -108,6 +109,17 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
108 token.value 109 token.value
109 } 110 }
110 111
112 pub fn descend_node_at_offset<N: ast::AstNode>(
113 &self,
114 node: &SyntaxNode,
115 offset: TextUnit,
116 ) -> Option<N> {
117 // Handle macro token cases
118 node.token_at_offset(offset)
119 .map(|token| self.descend_into_macros(token))
120 .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast))
121 }
122
111 pub fn original_range(&self, node: &SyntaxNode) -> FileRange { 123 pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
112 let node = self.find_file(node.clone()); 124 let node = self.find_file(node.clone());
113 original_range(self.db, node.as_ref()) 125 original_range(self.db, node.as_ref())
@@ -129,6 +141,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
129 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) 141 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
130 } 142 }
131 143
144 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
145 /// search up until it is of the target AstNode type
132 pub fn find_node_at_offset_with_macros<N: AstNode>( 146 pub fn find_node_at_offset_with_macros<N: AstNode>(
133 &self, 147 &self,
134 node: &SyntaxNode, 148 node: &SyntaxNode,
@@ -137,6 +151,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
137 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) 151 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
138 } 152 }
139 153
154 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
155 /// descend it and find again
156 pub fn find_node_at_offset_with_descend<N: AstNode>(
157 &self,
158 node: &SyntaxNode,
159 offset: TextUnit,
160 ) -> Option<N> {
161 if let Some(it) = find_node_at_offset(&node, offset) {
162 return Some(it);
163 }
164 self.descend_node_at_offset(&node, offset)
165 }
166
140 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { 167 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
141 self.analyze(expr.syntax()).type_of(self.db, &expr) 168 self.analyze(expr.syntax()).type_of(self.db, &expr)
142 } 169 }
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index e8afef328..10c12c910 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -17,7 +17,7 @@ use hir_def::{
17 AsMacroCall, DefWithBodyId, 17 AsMacroCall, DefWithBodyId,
18}; 18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; 20use hir_ty::InferenceResult;
21use ra_syntax::{ 21use ra_syntax::{
22 ast::{self, AstNode}, 22 ast::{self, AstNode},
23 SyntaxNode, SyntaxNodePtr, TextUnit, 23 SyntaxNode, SyntaxNodePtr, TextUnit,
@@ -103,10 +103,6 @@ impl SourceAnalyzer {
103 Some(res) 103 Some(res)
104 } 104 }
105 105
106 fn trait_env(&self, db: &dyn HirDatabase) -> Arc<TraitEnvironment> {
107 TraitEnvironment::lower(db, &self.resolver)
108 }
109
110 pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { 106 pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> {
111 let expr_id = match expr { 107 let expr_id = match expr {
112 ast::Expr::MacroCall(call) => { 108 ast::Expr::MacroCall(call) => {
@@ -117,15 +113,13 @@ impl SourceAnalyzer {
117 }?; 113 }?;
118 114
119 let ty = self.infer.as_ref()?[expr_id].clone(); 115 let ty = self.infer.as_ref()?[expr_id].clone();
120 let environment = self.trait_env(db); 116 Type::new_with_resolver(db, &self.resolver, ty)
121 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
122 } 117 }
123 118
124 pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> { 119 pub(crate) fn type_of_pat(&self, db: &dyn HirDatabase, pat: &ast::Pat) -> Option<Type> {
125 let pat_id = self.pat_id(pat)?; 120 let pat_id = self.pat_id(pat)?;
126 let ty = self.infer.as_ref()?[pat_id].clone(); 121 let ty = self.infer.as_ref()?[pat_id].clone();
127 let environment = self.trait_env(db); 122 Type::new_with_resolver(db, &self.resolver, ty)
128 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
129 } 123 }
130 124
131 pub(crate) fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 125 pub(crate) fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 3ea0ac230..746cc86ba 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -94,12 +94,16 @@ pub(crate) fn find_all_refs(
94 let sema = Semantics::new(db); 94 let sema = Semantics::new(db);
95 let syntax = sema.parse(position.file_id).syntax().clone(); 95 let syntax = sema.parse(position.file_id).syntax().clone();
96 96
97 let (opt_name, search_kind) = 97 let (opt_name, search_kind) = if let Some(name) =
98 if let Some(name) = get_struct_def_name_for_struct_literal_search(&syntax, position) { 98 get_struct_def_name_for_struct_literal_search(&sema, &syntax, position)
99 (Some(name), ReferenceKind::StructLiteral) 99 {
100 } else { 100 (Some(name), ReferenceKind::StructLiteral)
101 (find_node_at_offset::<ast::Name>(&syntax, position.offset), ReferenceKind::Other) 101 } else {
102 }; 102 (
103 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, position.offset),
104 ReferenceKind::Other,
105 )
106 };
103 107
104 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 108 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
105 109
@@ -131,7 +135,8 @@ fn find_name(
131 let range = name.syntax().text_range(); 135 let range = name.syntax().text_range();
132 return Some(RangeInfo::new(range, def)); 136 return Some(RangeInfo::new(range, def));
133 } 137 }
134 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; 138 let name_ref =
139 sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
135 let def = classify_name_ref(sema, &name_ref)?.definition(); 140 let def = classify_name_ref(sema, &name_ref)?.definition();
136 let range = name_ref.syntax().text_range(); 141 let range = name_ref.syntax().text_range();
137 Some(RangeInfo::new(range, def)) 142 Some(RangeInfo::new(range, def))
@@ -157,6 +162,7 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio
157} 162}
158 163
159fn get_struct_def_name_for_struct_literal_search( 164fn get_struct_def_name_for_struct_literal_search(
165 sema: &Semantics<RootDatabase>,
160 syntax: &SyntaxNode, 166 syntax: &SyntaxNode,
161 position: FilePosition, 167 position: FilePosition,
162) -> Option<ast::Name> { 168) -> Option<ast::Name> {
@@ -164,10 +170,18 @@ fn get_struct_def_name_for_struct_literal_search(
164 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN { 170 if right.kind() != SyntaxKind::L_CURLY && right.kind() != SyntaxKind::L_PAREN {
165 return None; 171 return None;
166 } 172 }
167 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, left.text_range().start()) { 173 if let Some(name) =
174 sema.find_node_at_offset_with_descend::<ast::Name>(&syntax, left.text_range().start())
175 {
168 return name.syntax().ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); 176 return name.syntax().ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name());
169 } 177 }
170 if find_node_at_offset::<ast::TypeParamList>(&syntax, left.text_range().start()).is_some() { 178 if sema
179 .find_node_at_offset_with_descend::<ast::TypeParamList>(
180 &syntax,
181 left.text_range().start(),
182 )
183 .is_some()
184 {
171 return left.ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name()); 185 return left.ancestors().find_map(ast::StructDef::cast).and_then(|l| l.name());
172 } 186 }
173 } 187 }
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 7d1190af9..9acc6158a 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -250,6 +250,63 @@ mod tests {
250 } 250 }
251 251
252 #[test] 252 #[test]
253 fn test_rename_for_macro_args_rev() {
254 test_rename(
255 r#"
256 macro_rules! foo {($i:ident) => {$i} }
257 fn main() {
258 let a = "test";
259 foo!(a<|>);
260 }"#,
261 "b",
262 r#"
263 macro_rules! foo {($i:ident) => {$i} }
264 fn main() {
265 let b = "test";
266 foo!(b);
267 }"#,
268 );
269 }
270
271 #[test]
272 fn test_rename_for_macro_define_fn() {
273 test_rename(
274 r#"
275 macro_rules! define_fn {($id:ident) => { fn $id{} }}
276 define_fn!(foo);
277 fn main() {
278 fo<|>o();
279 }"#,
280 "bar",
281 r#"
282 macro_rules! define_fn {($id:ident) => { fn $id{} }}
283 define_fn!(bar);
284 fn main() {
285 bar();
286 }"#,
287 );
288 }
289
290 #[test]
291 fn test_rename_for_macro_define_fn_rev() {
292 test_rename(
293 r#"
294 macro_rules! define_fn {($id:ident) => { fn $id{} }}
295 define_fn!(fo<|>o);
296 fn main() {
297 foo();
298 }"#,
299 "bar",
300 r#"
301 macro_rules! define_fn {($id:ident) => { fn $id{} }}
302 define_fn!(bar);
303 fn main() {
304 bar();
305 }"#,
306 );
307 }
308
309 #[test]
253 fn test_rename_for_param_inside() { 310 fn test_rename_for_param_inside() {
254 test_rename( 311 test_rename(
255 r#" 312 r#"
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index cf78d3e41..117454695 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -10,9 +10,7 @@ use hir::{DefWithBody, HasSource, ModuleSource, Semantics};
10use once_cell::unsync::Lazy; 10use once_cell::unsync::Lazy;
11use ra_db::{FileId, FileRange, SourceDatabaseExt}; 11use ra_db::{FileId, FileRange, SourceDatabaseExt};
12use ra_prof::profile; 12use ra_prof::profile;
13use ra_syntax::{ 13use ra_syntax::{ast, match_ast, AstNode, TextRange, TextUnit};
14 algo::find_node_at_offset, ast, match_ast, AstNode, TextRange, TextUnit, TokenAtOffset,
15};
16use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
17use test_utils::tested_by; 15use test_utils::tested_by;
18 16
@@ -219,21 +217,11 @@ impl Definition {
219 continue; 217 continue;
220 } 218 }
221 219
222 let name_ref = 220 let name_ref: ast::NameRef =
223 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&tree, offset) { 221 if let Some(name_ref) = sema.find_node_at_offset_with_descend(&tree, offset) {
224 name_ref 222 name_ref
225 } else { 223 } else {
226 // Handle macro token cases 224 continue;
227 let token = match tree.token_at_offset(offset) {
228 TokenAtOffset::None => continue,
229 TokenAtOffset::Single(t) => t,
230 TokenAtOffset::Between(_, t) => t,
231 };
232 let expanded = sema.descend_into_macros(token);
233 match ast::NameRef::cast(expanded.parent()) {
234 Some(name_ref) => name_ref,
235 _ => continue,
236 }
237 }; 225 };
238 226
239 // FIXME: reuse sb 227 // FIXME: reuse sb
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index c2857dbfc..c7f9bd873 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -6,7 +6,7 @@ use std::{
6}; 6};
7 7
8use anyhow::{Context, Result}; 8use anyhow::{Context, Result};
9use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId}; 9use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
10use ra_arena::{Arena, Idx}; 10use ra_arena::{Arena, Idx};
11use ra_cargo_watch::run_cargo; 11use ra_cargo_watch::run_cargo;
12use ra_db::Edition; 12use ra_db::Edition;
@@ -254,7 +254,7 @@ pub fn load_out_dirs(
254 "check".to_string(), 254 "check".to_string(),
255 "--message-format=json".to_string(), 255 "--message-format=json".to_string(),
256 "--manifest-path".to_string(), 256 "--manifest-path".to_string(),
257 format!("{}", cargo_toml.display()), 257 cargo_toml.display().to_string(),
258 ]; 258 ];
259 259
260 if cargo_features.all_features { 260 if cargo_features.all_features {
@@ -263,19 +263,15 @@ pub fn load_out_dirs(
263 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 263 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
264 // https://github.com/oli-obk/cargo_metadata/issues/79 264 // https://github.com/oli-obk/cargo_metadata/issues/79
265 args.push("--no-default-features".to_string()); 265 args.push("--no-default-features".to_string());
266 } else if !cargo_features.features.is_empty() { 266 } else {
267 for feature in &cargo_features.features { 267 args.extend(cargo_features.features.iter().cloned());
268 args.push(feature.clone());
269 }
270 } 268 }
271 269
272 let mut res = FxHashMap::default(); 270 let mut acc = FxHashMap::default();
273 let mut child = run_cargo(&args, cargo_toml.parent(), &mut |message| { 271 let res = run_cargo(&args, cargo_toml.parent(), &mut |message| {
274 match message { 272 match message {
275 Message::BuildScriptExecuted(message) => { 273 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
276 let package_id = message.package_id; 274 acc.insert(package_id, out_dir);
277 let out_dir = message.out_dir;
278 res.insert(package_id, out_dir);
279 } 275 }
280 276
281 Message::CompilerArtifact(_) => (), 277 Message::CompilerArtifact(_) => (),
@@ -285,6 +281,9 @@ pub fn load_out_dirs(
285 true 281 true
286 }); 282 });
287 283
288 let _ = child.wait(); 284 if let Err(err) = res {
289 res 285 log::error!("Failed to load outdirs: {:?}", err);
286 }
287
288 acc
290} 289}
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 2002d3e2a..3255eefb9 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -7,13 +7,18 @@ use crate::{
7 project_root, 7 project_root,
8}; 8};
9 9
10pub fn run_dist(version: &str, release_tag: &str) -> Result<()> { 10pub struct ClientOpts {
11 pub version: String,
12 pub release_tag: String,
13}
14
15pub fn run_dist(client_opts: Option<ClientOpts>) -> Result<()> {
11 let dist = project_root().join("dist"); 16 let dist = project_root().join("dist");
12 rm_rf(&dist)?; 17 rm_rf(&dist)?;
13 fs2::create_dir_all(&dist)?; 18 fs2::create_dir_all(&dist)?;
14 19
15 if cfg!(target_os = "linux") { 20 if let Some(ClientOpts { version, release_tag }) = client_opts {
16 dist_client(version, release_tag)?; 21 dist_client(&version, &release_tag)?;
17 } 22 }
18 dist_server()?; 23 dist_server()?;
19 Ok(()) 24 Ok(())
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index aafa73610..a9adcfba4 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -13,7 +13,7 @@ use std::env;
13use pico_args::Arguments; 13use pico_args::Arguments;
14use xtask::{ 14use xtask::{
15 codegen::{self, Mode}, 15 codegen::{self, Mode},
16 dist::run_dist, 16 dist::{run_dist, ClientOpts},
17 install::{ClientOpt, InstallCmd, ServerOpt}, 17 install::{ClientOpt, InstallCmd, ServerOpt},
18 not_bash::pushd, 18 not_bash::pushd,
19 pre_commit, project_root, run_clippy, run_fuzzer, run_pre_cache, run_release, run_rustfmt, 19 pre_commit, project_root, run_clippy, run_fuzzer, run_pre_cache, run_release, run_rustfmt,
@@ -103,10 +103,16 @@ FLAGS:
103 run_release(dry_run) 103 run_release(dry_run)
104 } 104 }
105 "dist" => { 105 "dist" => {
106 let version: String = args.value_from_str("--version")?; 106 let client_opts = if args.contains("--client") {
107 let release_tag: String = args.value_from_str("--tag")?; 107 Some(ClientOpts {
108 version: args.value_from_str("--version")?,
109 release_tag: args.value_from_str("--tag")?,
110 })
111 } else {
112 None
113 };
108 args.finish()?; 114 args.finish()?;
109 run_dist(&version, &release_tag) 115 run_dist(client_opts)
110 } 116 }
111 _ => { 117 _ => {
112 eprintln!( 118 eprintln!(