Skip to content

Commit 51e3775

Browse files
committed
Auto merge of rust-lang#17915 - Veykril:offline-no-deps, r=Veykril
feat: Make rust-analyzer work partially when offline Helps out with rust-lang/rust-analyzer#12499 a bit
2 parents eb12861 + 324cf83 commit 51e3775

File tree

7 files changed

+85
-24
lines changed

7 files changed

+85
-24
lines changed

src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub struct CargoWorkspace {
3333
workspace_root: AbsPathBuf,
3434
target_directory: AbsPathBuf,
3535
manifest_path: ManifestPath,
36+
// Whether this workspace was queried with `--no-deps`.
37+
no_deps: bool,
3638
}
3739

3840
impl ops::Index<Package> for CargoWorkspace {
@@ -259,6 +261,18 @@ impl CargoWorkspace {
259261
sysroot: &Sysroot,
260262
locked: bool,
261263
progress: &dyn Fn(String),
264+
) -> anyhow::Result<cargo_metadata::Metadata> {
265+
Self::fetch_metadata_(cargo_toml, current_dir, config, sysroot, locked, false, progress)
266+
}
267+
268+
fn fetch_metadata_(
269+
cargo_toml: &ManifestPath,
270+
current_dir: &AbsPath,
271+
config: &CargoConfig,
272+
sysroot: &Sysroot,
273+
locked: bool,
274+
no_deps: bool,
275+
progress: &dyn Fn(String),
262276
) -> anyhow::Result<cargo_metadata::Metadata> {
263277
let targets = find_list_of_build_targets(config, cargo_toml, sysroot);
264278

@@ -314,6 +328,9 @@ impl CargoWorkspace {
314328
if locked {
315329
other_options.push("--locked".to_owned());
316330
}
331+
if no_deps {
332+
other_options.push("--no-deps".to_owned());
333+
}
317334
meta.other_options(other_options);
318335

319336
// FIXME: Fetching metadata is a slow process, as it might require
@@ -324,6 +341,22 @@ impl CargoWorkspace {
324341
(|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
325342
let output = meta.cargo_command().output()?;
326343
if !output.status.success() {
344+
if !no_deps {
345+
// If we failed to fetch metadata with deps, try again without them.
346+
// This makes r-a still work partially when offline.
347+
if let Ok(metadata) = Self::fetch_metadata_(
348+
cargo_toml,
349+
current_dir,
350+
config,
351+
sysroot,
352+
locked,
353+
true,
354+
progress,
355+
) {
356+
return Ok(metadata);
357+
}
358+
}
359+
327360
return Err(cargo_metadata::Error::CargoMetadata {
328361
stderr: String::from_utf8(output.stderr)?,
329362
});
@@ -431,8 +464,8 @@ impl CargoWorkspace {
431464
pkg_data.targets.push(tgt);
432465
}
433466
}
434-
let resolve = meta.resolve.expect("metadata executed with deps");
435-
for mut node in resolve.nodes {
467+
let no_deps = meta.resolve.is_none();
468+
for mut node in meta.resolve.map_or_else(Vec::new, |it| it.nodes) {
436469
let &source = pkg_by_id.get(&node.id).unwrap();
437470
node.deps.sort_by(|a, b| a.pkg.cmp(&b.pkg));
438471
let dependencies = node
@@ -451,7 +484,14 @@ impl CargoWorkspace {
451484

452485
let target_directory = AbsPathBuf::assert(meta.target_directory);
453486

454-
CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path }
487+
CargoWorkspace {
488+
packages,
489+
targets,
490+
workspace_root,
491+
target_directory,
492+
manifest_path,
493+
no_deps,
494+
}
455495
}
456496

457497
pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
@@ -533,6 +573,10 @@ impl CargoWorkspace {
533573
fn is_unique(&self, name: &str) -> bool {
534574
self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
535575
}
576+
577+
pub fn no_deps(&self) -> bool {
578+
self.no_deps
579+
}
536580
}
537581

538582
fn find_list_of_build_targets(

src/tools/rust-analyzer/crates/project-model/src/sysroot.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -372,18 +372,19 @@ impl Sysroot {
372372
.flatten()
373373
};
374374

375-
let resolve = res.resolve.as_mut().expect("metadata executed with deps");
376-
resolve.nodes.retain_mut(|node| {
377-
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
378-
node.deps.iter_mut().for_each(|dep| {
379-
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
380-
if let Some((_, real)) = real_pkg {
381-
dep.pkg = real;
382-
}
375+
if let Some(resolve) = res.resolve.as_mut() {
376+
resolve.nodes.retain_mut(|node| {
377+
// Replace `rustc-std-workspace` crate with the actual one in the dependency list
378+
node.deps.iter_mut().for_each(|dep| {
379+
let real_pkg = patches.clone().find(|((_, fake_id), _)| *fake_id == dep.pkg);
380+
if let Some((_, real)) = real_pkg {
381+
dep.pkg = real;
382+
}
383+
});
384+
// Remove this node if it's a fake one
385+
!patches.clone().any(|((_, fake), _)| fake == node.id)
383386
});
384-
// Remove this node if it's a fake one
385-
!patches.clone().any(|((_, fake), _)| fake == node.id)
386-
});
387+
}
387388
// Remove the fake ones from the package list
388389
patches.map(|((idx, _), _)| idx).sorted().rev().for_each(|idx| {
389390
res.packages.remove(idx);

src/tools/rust-analyzer/crates/project-model/src/workspace.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,14 +441,15 @@ impl ProjectWorkspace {
441441
) -> anyhow::Result<WorkspaceBuildScripts> {
442442
match &self.kind {
443443
ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
444-
| ProjectWorkspaceKind::Cargo { cargo, .. } => {
444+
| ProjectWorkspaceKind::Cargo { cargo, .. }
445+
if !cargo.no_deps() =>
446+
{
445447
WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot)
446448
.with_context(|| {
447449
format!("Failed to run build scripts for {}", cargo.workspace_root())
448450
})
449451
}
450-
ProjectWorkspaceKind::DetachedFile { cargo: None, .. }
451-
| ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()),
452+
_ => Ok(WorkspaceBuildScripts::default()),
452453
}
453454
}
454455

src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl DiagnosticCollection {
7575
flycheck_id: usize,
7676
file_id: FileId,
7777
diagnostic: lsp_types::Diagnostic,
78-
fix: Option<Fix>,
78+
fix: Option<Box<Fix>>,
7979
) {
8080
let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default();
8181
for existing_diagnostic in diagnostics.iter() {
@@ -84,8 +84,10 @@ impl DiagnosticCollection {
8484
}
8585
}
8686

87-
let check_fixes = Arc::make_mut(&mut self.check_fixes);
88-
check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix);
87+
if let Some(fix) = fix {
88+
let check_fixes = Arc::make_mut(&mut self.check_fixes);
89+
check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().push(*fix);
90+
}
8991
diagnostics.push(diagnostic);
9092
self.changes.insert(file_id);
9193
}

src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ fn resolve_path(
170170

171171
struct SubDiagnostic {
172172
related: lsp_types::DiagnosticRelatedInformation,
173-
suggested_fix: Option<Fix>,
173+
suggested_fix: Option<Box<Fix>>,
174174
}
175175

176176
enum MappedRustChildDiagnostic {
@@ -241,7 +241,7 @@ fn map_rust_child_diagnostic(
241241
location: location(config, workspace_root, spans[0], snap),
242242
message: message.clone(),
243243
},
244-
suggested_fix: Some(Fix {
244+
suggested_fix: Some(Box::new(Fix {
245245
ranges: spans
246246
.iter()
247247
.map(|&span| location(config, workspace_root, span, snap).range)
@@ -260,7 +260,7 @@ fn map_rust_child_diagnostic(
260260
data: None,
261261
command: None,
262262
},
263-
}),
263+
})),
264264
})
265265
}
266266
}
@@ -269,7 +269,7 @@ fn map_rust_child_diagnostic(
269269
pub(crate) struct MappedRustDiagnostic {
270270
pub(crate) url: lsp_types::Url,
271271
pub(crate) diagnostic: lsp_types::Diagnostic,
272-
pub(crate) fix: Option<Fix>,
272+
pub(crate) fix: Option<Box<Fix>>,
273273
}
274274

275275
/// Converts a Rust root diagnostic to LSP form

src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ struct FlycheckActor {
218218
status: FlycheckStatus,
219219
}
220220

221+
#[allow(clippy::large_enum_variant)]
221222
enum Event {
222223
RequestStateChange(StateChange),
223224
CheckEvent(Option<CargoCheckMessage>),

src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ impl GlobalState {
165165
self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
166166

167167
for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
168+
if matches!(
169+
&ws.kind,
170+
ProjectWorkspaceKind::Cargo { cargo, .. } | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
171+
if cargo.no_deps()
172+
) {
173+
status.health |= lsp_ext::Health::Warning;
174+
format_to!(
175+
message,
176+
"Workspace `{}` has been queried without dependencies, connecting to crates.io might have failed.\n\n",
177+
ws.manifest_or_root()
178+
);
179+
}
168180
if let Some(err) = ws.sysroot.error() {
169181
status.health |= lsp_ext::Health::Warning;
170182
format_to!(

0 commit comments

Comments
 (0)