arena: FxHashMap<CrateId, CrateData>,
}
+#[derive(Debug)]
+pub struct CyclicDependencies;
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CrateId(pub u32);
assert!(prev.is_none());
crate_id
}
- pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) {
- let mut visited = FxHashSet::default();
- if self.dfs_find(from, to, &mut visited) {
- panic!("Cycle dependencies found.")
+ pub fn add_dep(
+ &mut self,
+ from: CrateId,
+ name: SmolStr,
+ to: CrateId,
+ ) -> Result<(), CyclicDependencies> {
+ if self.dfs_find(from, to, &mut FxHashSet::default()) {
+ return Err(CyclicDependencies);
}
- self.arena.get_mut(&from).unwrap().add_dep(name, to)
+ Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to))
}
pub fn is_empty(&self) -> bool {
self.arena.is_empty()
}
}
-#[cfg(test)]
-mod tests {
- use super::{CrateGraph, FxHashMap, FileId, SmolStr};
-
- #[test]
- #[should_panic]
- fn it_should_painc_because_of_cycle_dependencies() {
- let mut graph = CrateGraph::default();
- let crate1 = graph.add_crate_root(FileId(1u32));
- let crate2 = graph.add_crate_root(FileId(2u32));
- let crate3 = graph.add_crate_root(FileId(3u32));
- graph.add_dep(crate1, SmolStr::new("crate2"), crate2);
- graph.add_dep(crate2, SmolStr::new("crate3"), crate3);
- graph.add_dep(crate3, SmolStr::new("crate1"), crate1);
- }
-
- #[test]
- fn it_works() {
- let mut graph = CrateGraph {
- arena: FxHashMap::default(),
- };
- let crate1 = graph.add_crate_root(FileId(1u32));
- let crate2 = graph.add_crate_root(FileId(2u32));
- let crate3 = graph.add_crate_root(FileId(3u32));
- graph.add_dep(crate1, SmolStr::new("crate2"), crate2);
- graph.add_dep(crate2, SmolStr::new("crate3"), crate3);
- }
-}
-
salsa::query_group! {
pub trait FilesDatabase: salsa::Database {
/// Text of the file.
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::{CrateGraph, FileId, SmolStr};
+
+ #[test]
+ fn it_should_painc_because_of_cycle_dependencies() {
+ let mut graph = CrateGraph::default();
+ let crate1 = graph.add_crate_root(FileId(1u32));
+ let crate2 = graph.add_crate_root(FileId(2u32));
+ let crate3 = graph.add_crate_root(FileId(3u32));
+ assert!(graph
+ .add_dep(crate1, SmolStr::new("crate2"), crate2)
+ .is_ok());
+ assert!(graph
+ .add_dep(crate2, SmolStr::new("crate3"), crate3)
+ .is_ok());
+ assert!(graph
+ .add_dep(crate3, SmolStr::new("crate1"), crate1)
+ .is_err());
+ }
+
+ #[test]
+ fn it_works() {
+ let mut graph = CrateGraph::default();
+ let crate1 = graph.add_crate_root(FileId(1u32));
+ let crate2 = graph.add_crate_root(FileId(2u32));
+ let crate3 = graph.add_crate_root(FileId(3u32));
+ assert!(graph
+ .add_dep(crate1, SmolStr::new("crate2"), crate2)
+ .is_ok());
+ assert!(graph
+ .add_dep(crate2, SmolStr::new("crate3"), crate3)
+ .is_ok());
+ }
+}
let mut crate_graph = CrateGraph::default();
let main_crate = crate_graph.add_crate_root(main_id);
let lib_crate = crate_graph.add_crate_root(lib_id);
- crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);
+ crate_graph
+ .add_dep(main_crate, "test_crate".into(), lib_crate)
+ .unwrap();
db.set_crate_graph(crate_graph);
let mut crate_graph = CrateGraph::default();
let main_crate = crate_graph.add_crate_root(main_id);
let lib_crate = crate_graph.add_crate_root(lib_id);
- crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);
+ crate_graph
+ .add_dep(main_crate, "test_crate".into(), lib_crate)
+ .unwrap();
db.set_crate_graph(crate_graph);
let mut crate_graph = CrateGraph::default();
let main_crate = crate_graph.add_crate_root(main_id);
let lib_crate = crate_graph.add_crate_root(lib_id);
- crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);
+ crate_graph
+ .add_dep(main_crate, "test_crate".into(), lib_crate)
+ .unwrap();
db.set_crate_graph(crate_graph);
let file = db.source_file(position.file_id);
let syntax = file.syntax();
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
- let navs = reference_definition(db, position.file_id, name_ref)?;
- return Ok(Some(RangeInfo::new(name_ref.syntax().range(), navs)));
+ let navs = reference_definition(db, position.file_id, name_ref)?.to_vec();
+ return Ok(Some(RangeInfo::new(
+ name_ref.syntax().range(),
+ navs.to_vec(),
+ )));
}
if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
let navs = ctry!(name_definition(db, position.file_id, name)?);
Ok(None)
}
+pub(crate) enum ReferenceResult {
+ Exact(NavigationTarget),
+ Approximate(Vec<NavigationTarget>),
+}
+
+impl ReferenceResult {
+ fn to_vec(self) -> Vec<NavigationTarget> {
+ use self::ReferenceResult::*;
+ match self {
+ Exact(target) => vec![target],
+ Approximate(vec) => vec,
+ }
+ }
+}
+
pub(crate) fn reference_definition(
db: &RootDatabase,
file_id: FileId,
name_ref: &ast::NameRef,
-) -> Cancelable<Vec<NavigationTarget>> {
+) -> Cancelable<ReferenceResult> {
+ use self::ReferenceResult::*;
if let Some(fn_descr) =
hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
{
// First try to resolve the symbol locally
if let Some(entry) = scope.resolve_local_name(name_ref) {
let nav = NavigationTarget::from_scope_entry(file_id, &entry);
- return Ok(vec![nav]);
+ return Ok(Exact(nav));
};
}
// Then try module name resolution
let resolved = module.resolve_path(db, &path)?;
if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)?)? {
- return Ok(vec![target]);
+ return Ok(Exact(target));
}
}
}
.into_iter()
.map(NavigationTarget::from_symbol)
.collect();
- Ok(navs)
+ Ok(Approximate(navs))
}
fn name_definition(
let mut range = None;
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
- let navs = crate::goto_definition::reference_definition(db, position.file_id, name_ref)?;
- for nav in navs {
- res.extend(doc_text_for(db, nav)?)
+ use crate::goto_definition::{ReferenceResult::*, reference_definition};
+ let ref_result = reference_definition(db, position.file_id, name_ref)?;
+ match ref_result {
+ Exact(nav) => res.extend(doc_text_for(db, nav)?),
+ Approximate(navs) => {
+ res.push("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits. \nThese methods were found instead:".to_string());
+ for nav in navs {
+ res.extend(doc_text_for(db, nav)?)
+ }
+ }
}
if !res.is_empty() {
range = Some(name_ref.syntax().range())
file_id: position.file_id,
range: node.range(),
};
- res.extend(type_of(db, frange)?);
+ res.extend(type_of(db, frange)?.map(Into::into));
range = Some(node.range());
};
pub enum RunnableKind {
Test { name: String },
TestMod { path: String },
+ Bench { name: String },
Bin,
}
RunnableKind::Test {
name: name.to_string(),
}
+ } else if fn_def.has_atom_attr("bench") {
+ RunnableKind::Bench {
+ name: name.to_string(),
+ }
} else {
return None;
};
res.push(path.to_string());
res.push("--nocapture".to_string());
}
+ RunnableKind::Bench { name } => {
+ res.push("bench".to_string());
+ if let Some(spec) = spec {
+ spec.push_to(&mut res);
+ }
+ res.push("--".to_string());
+ res.push(name.to_string());
+ res.push("--nocapture".to_string());
+ }
RunnableKind::Bin => {
res.push("run".to_string());
if let Some(spec) = spec {
use gen_lsp_server::ErrorCode;
use languageserver_types::{
- CodeActionResponse, Command, CodeLens, Diagnostic, DiagnosticSeverity, DocumentFormattingParams,
- DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
- FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind,
- ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams,
- SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit,
+ CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
+ DocumentFormattingParams, DocumentHighlight, DocumentSymbol, Documentation, FoldingRange,
+ FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
+ MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
+ RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
+ WorkspaceEdit,
};
use ra_ide_api::{
- FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, RangeInfo,
+ FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity,
};
-use ra_syntax::{TextUnit, AstNode};
+use ra_syntax::{AstNode, TextUnit};
use rustc_hash::FxHashMap;
use serde_json::to_value;
use std::io::Write;
use crate::{
- cargo_target_spec::{CargoTargetSpec, runnable_args},
+ cargo_target_spec::{runnable_args, CargoTargetSpec},
conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith},
req::{self, Decoration},
server_world::ServerWorld,
label: match &runnable.kind {
RunnableKind::Test { name } => format!("test {}", name),
RunnableKind::TestMod { path } => format!("test-mod {}", path),
+ RunnableKind::Bench { name } => format!("bench {}", name),
RunnableKind::Bin => "run binary".to_string(),
},
bin: "cargo".to_string(),
let mut lenses: Vec<CodeLens> = Default::default();
for runnable in world.analysis().runnables(file_id)? {
- match &runnable.kind {
- RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => {
- let args = runnable_args(&world, file_id, &runnable.kind)?;
-
- let range = runnable.range.conv_with(&line_index);
-
- // This represents the actual command that will be run.
- let r: req::Runnable = req::Runnable {
- range,
- label: Default::default(),
- bin: "cargo".into(),
- args,
- env: Default::default(),
- };
+ let title = match &runnable.kind {
+ RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => Some("Run Test"),
+ RunnableKind::Bench { name: _ } => Some("Run Bench"),
+ _ => None,
+ };
- let lens = CodeLens {
- range,
- command: Some(Command {
- title: "Run Test".into(),
- command: "ra-lsp.run-single".into(),
- arguments: Some(vec![to_value(r).unwrap()]),
- }),
- data: None,
- };
+ if let Some(title) = title {
+ let args = runnable_args(&world, file_id, &runnable.kind)?;
+ let range = runnable.range.conv_with(&line_index);
+
+ // This represents the actual command that will be run.
+ let r: req::Runnable = req::Runnable {
+ range,
+ label: Default::default(),
+ bin: "cargo".into(),
+ args,
+ env: Default::default(),
+ };
- lenses.push(lens);
- }
- _ => continue,
- };
+ let lens = CodeLens {
+ range,
+ command: Some(Command {
+ title: title.into(),
+ command: "ra-lsp.run-single".into(),
+ arguments: Some(vec![to_value(r).unwrap()]),
+ }),
+ data: None,
+ };
+
+ lenses.push(lens);
+ }
}
return Ok(Some(lenses));
if let (Some(&from), Some(&to)) =
(sysroot_crates.get(&from), sysroot_crates.get(&to))
{
- crate_graph.add_dep(from, name.clone(), to);
+ if let Err(_) = crate_graph.add_dep(from, name.clone(), to) {
+ log::error!("cyclic dependency between sysroot crates")
+ }
}
}
}
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
if let Some(to) = lib_tgt {
if to != from {
- crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to);
+ if let Err(_) =
+ crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to)
+ {
+ log::error!(
+ "cyclic dependency between targets of {}",
+ pkg.name(&ws.cargo)
+ )
+ }
}
}
if let Some(std) = libstd {
- crate_graph.add_dep(from, "std".into(), std);
+ if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
+ log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo))
+ }
}
}
}
for dep in pkg.dependencies(&ws.cargo) {
if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
for &from in pkg_crates.get(&pkg).into_iter().flatten() {
- crate_graph.add_dep(from, dep.name.clone(), to);
+ if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
+ log::error!(
+ "cyclic dependency {} -> {}",
+ pkg.name(&ws.cargo),
+ dep.pkg.name(&ws.cargo)
+ )
+ }
}
}
}
}
export async function handle(change: SourceChange) {
- const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(change.workspaceEdit);
+ const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(
+ change.workspaceEdit
+ );
let created;
let moved;
if (change.workspaceEdit.documentChanges) {
SourceChange
} from './apply_source_change';
-
export async function handle(event: { text: string }): Promise<boolean> {
const editor = vscode.window.activeTextEditor;
if (
cwd: '.',
env: definition.env
};
- const exec = new vscode.ShellExecution(definition.command, definition.args, execOption);
+ const exec = new vscode.ShellExecution(
+ definition.command,
+ definition.args,
+ execOption
+ );
const f = vscode.workspace.workspaceFolders![0];
const t = new vscode.Task(
exec,
['$rustc']
);
- t.presentationOptions.clear = true
+ t.presentationOptions.clear = true;
return t;
}
task.group = vscode.TaskGroup.Build;
task.presentationOptions = {
reveal: vscode.TaskRevealKind.Always,
- panel: vscode.TaskPanelKind.Dedicated,
+ panel: vscode.TaskPanelKind.Dedicated
};
-
+
return vscode.tasks.executeTask(task);
-}
\ No newline at end of file
+}
return await original(...args);
}
});
- } catch(_) {
- vscode.window.showWarningMessage('Enhanced typing feature is disabled because of incompatibility with VIM extension');
+ } catch (_) {
+ vscode.window.showWarningMessage(
+ 'Enhanced typing feature is disabled because of incompatibility with VIM extension'
+ );
}
}