Repository: rust-analyzer/rust-analyzer
Pull request #396 (2018-12-31 23:03:38)

Fix the `panic` found whilst fuzzing
This occurred when a non-ascii character was used in an ascii escape, for example in the motivating example: `if'\xɿ`, which can be further simplified to `'\xɿ`.


Patch:
diff --git a/.cargo/config b/.cargo/config
index b9db30c969..c319d33f24 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,16 +1,10 @@
 [alias]
 # Automatically generates the ast and syntax kinds files
-gen-syntax   = "run --package tools --bin tools -- gen-syntax"
-# Extracts the tests from 
-gen-tests    = "run --package tools --bin tools -- gen-tests"
-# Installs the visual studio code extension
+gen-syntax =   "run --package tools --bin tools -- gen-syntax"
+gen-tests =    "run --package tools --bin tools -- gen-tests"
 install-code = "run --package tools --bin tools -- install-code"
-# Formats the full repository or installs the git hook to do it automatically.
-format       = "run --package tools --bin tools -- format"
-format-hook  = "run --package tools --bin tools -- format-hook"
-# Runs the fuzzing test suite (currently only parser)
-fuzz-tests   = "run --package tools --bin tools -- fuzz-tests"
+format =       "run --package tools --bin tools -- format"
+format-hook =  "run --package tools --bin tools -- format-hook"
 
-render-test  = "run --package ra_cli -- render-test"
-# Parse a file. This should be piped the file contents
-parse        = "run --package ra_cli -- parse"
+render-test =  "run --package ra_cli -- render-test"
+parse =        "run --package ra_cli -- parse"
diff --git a/crates/ra_analysis/src/extend_selection.rs b/crates/ra_analysis/src/extend_selection.rs
index 805e9059ef..cde6ee1018 100644
--- a/crates/ra_analysis/src/extend_selection.rs
+++ b/crates/ra_analysis/src/extend_selection.rs
@@ -1,6 +1,6 @@
 use ra_db::SyntaxDatabase;
 use ra_syntax::{
-    SyntaxNodeRef, AstNode, SourceFileNode,
+    SyntaxNodeRef, AstNode,
     ast, algo::find_covering_node,
 };
 
@@ -11,23 +11,18 @@ use crate::{
 
 pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
     let source_file = db.source_file(frange.file_id);
-    if let Some(range) = extend_selection_in_macro(db, &source_file, frange) {
-        return range;
+    if let Some(macro_call) = find_macro_call(source_file.syntax(), frange.range) {
+        if let Some(exp) = crate::macros::expand(db, frange.file_id, macro_call) {
+            if let Some(dst_range) = exp.map_range_forward(frange.range) {
+                if let Some(dst_range) = ra_editor::extend_selection(exp.source_file(), dst_range) {
+                    if let Some(src_range) = exp.map_range_back(dst_range) {
+                        return src_range;
+                    }
+                }
+            }
+        }
     }
-    ra_editor::extend_selection(source_file.syntax(), frange.range).unwrap_or(frange.range)
-}
-
-fn extend_selection_in_macro(
-    db: &RootDatabase,
-    source_file: &SourceFileNode,
-    frange: FileRange,
-) -> Option<TextRange> {
-    let macro_call = find_macro_call(source_file.syntax(), frange.range)?;
-    let exp = crate::macros::expand(db, frange.file_id, macro_call)?;
-    let dst_range = exp.map_range_forward(frange.range)?;
-    let dst_range = ra_editor::extend_selection(exp.source_file().syntax(), dst_range)?;
-    let src_range = exp.map_range_back(dst_range)?;
-    Some(src_range)
+    ra_editor::extend_selection(&source_file, frange.range).unwrap_or(frange.range)
 }
 
 fn find_macro_call(node: SyntaxNodeRef, range: TextRange) -> Option<ast::MacroCall> {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5669aa94d3..5ed374c791 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -181,28 +181,6 @@ impl AnalysisImpl {
         };
         Ok(query.search(&buf))
     }
-
-    pub(crate) fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> {
-        let descr = match source_binder::module_from_position(&*self.db, position)? {
-            None => return Ok(None),
-            Some(it) => it,
-        };
-        let name = match descr.name() {
-            None => return Ok(None),
-            Some(it) => it.to_string(),
-        };
-
-        let modules = descr.path_to_root();
-
-        let path = modules
-            .iter()
-            .filter_map(|s| s.name())
-            .skip(1) // name is already part of the string.
-            .fold(name, |path, it| format!("{}::{}", it, path));
-
-        Ok(Some(path.to_string()))
-    }
-
     /// This returns `Vec` because a module may be included from several places. We
     /// don't handle this case yet though, so the Vec has length at most one.
     pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index e6cfaecc3c..e561685100 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -15,7 +15,6 @@ mod imp;
 mod completion;
 mod symbol_index;
 pub mod mock_analysis;
-mod runnables;
 
 mod extend_selection;
 mod syntax_highlighting;
@@ -34,12 +33,10 @@ use crate::{
     symbol_index::SymbolIndex,
 };
 
-pub use crate::{
-    completion::{CompletionItem, CompletionItemKind, InsertText},
-    runnables::{Runnable, RunnableKind}
-};
+pub use crate::completion::{CompletionItem, CompletionItemKind, InsertText};
 pub use ra_editor::{
-    FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity
+    FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode,
+    Severity
 };
 pub use hir::FnSignatureInfo;
 
@@ -339,9 +336,6 @@ impl Analysis {
     pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
         self.imp.parent_module(position)
     }
-    pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> {
-        self.imp.module_path(position)
-    }
     pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
         self.imp.crate_for(file_id)
     }
@@ -350,7 +344,7 @@ impl Analysis {
     }
     pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
         let file = self.imp.file_syntax(file_id);
-        Ok(runnables::runnables(self, &file, file_id))
+        Ok(ra_editor::runnables(&file))
     }
     pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
         syntax_highlighting::highlight(&*self.imp.db, file_id)
diff --git a/crates/ra_analysis/src/runnables.rs b/crates/ra_analysis/src/runnables.rs
deleted file mode 100644
index 61ca0930a7..0000000000
--- a/crates/ra_analysis/src/runnables.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use ra_syntax::{
-    ast::{self, AstNode, NameOwner, ModuleItemOwner},
-    SourceFileNode, TextRange, SyntaxNodeRef,
-    TextUnit,
-};
-use crate::{
-    Analysis, FileId, FilePosition
-};
-
-#[derive(Debug)]
-pub struct Runnable {
-    pub range: TextRange,
-    pub kind: RunnableKind,
-}
-
-#[derive(Debug)]
-pub enum RunnableKind {
-    Test { name: String },
-    TestMod { path: String },
-    Bin,
-}
-
-pub fn runnables(
-    analysis: &Analysis,
-    file_node: &SourceFileNode,
-    file_id: FileId,
-) -> Vec<Runnable> {
-    file_node
-        .syntax()
-        .descendants()
-        .filter_map(|i| runnable(analysis, i, file_id))
-        .collect()
-}
-
-fn runnable<'a>(analysis: &Analysis, item: SyntaxNodeRef<'a>, file_id: FileId) -> Option<Runnable> {
-    if let Some(f) = ast::FnDef::cast(item) {
-        let name = f.name()?.text();
-        let kind = if name == "main" {
-            RunnableKind::Bin
-        } else if f.has_atom_attr("test") {
-            RunnableKind::Test {
-                name: name.to_string(),
-            }
-        } else {
-            return None;
-        };
-        Some(Runnable {
-            range: f.syntax().range(),
-            kind,
-        })
-    } else if let Some(m) = ast::Module::cast(item) {
-        if m.item_list()?
-            .items()
-            .map(ast::ModuleItem::syntax)
-            .filter_map(ast::FnDef::cast)
-            .any(|f| f.has_atom_attr("test"))
-        {
-            let postition = FilePosition {
-                file_id,
-                offset: m.syntax().range().start() + TextUnit::from_usize(1),
-            };
-            analysis.module_path(postition).ok()?.map(|path| Runnable {
-                range: m.syntax().range(),
-                kind: RunnableKind::TestMod { path },
-            })
-        } else {
-            None
-        }
-    } else {
-        None
-    }
-}
diff --git a/crates/ra_analysis/src/syntax_highlighting.rs b/crates/ra_analysis/src/syntax_highlighting.rs
index 7e9139a740..38219da71d 100644
--- a/crates/ra_analysis/src/syntax_highlighting.rs
+++ b/crates/ra_analysis/src/syntax_highlighting.rs
@@ -9,14 +9,14 @@ use crate::{
 
 pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
     let source_file = db.source_file(file_id);
-    let mut res = ra_editor::highlight(source_file.syntax());
+    let mut res = ra_editor::highlight(&source_file);
     for macro_call in source_file
         .syntax()
         .descendants()
         .filter_map(ast::MacroCall::cast)
     {
         if let Some(exp) = crate::macros::expand(db, file_id, macro_call) {
-            let mapped_ranges = ra_editor::highlight(exp.source_file().syntax())
+            let mapped_ranges = ra_editor::highlight(exp.source_file())
                 .into_iter()
                 .filter_map(|r| {
                     let mapped_range = exp.map_range_back(r.range)?;
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index a3b856aa94..939f7fe77d 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -102,7 +102,7 @@ fn selections(file: &SourceFileNode, start: u32, end: u32) -> String {
     let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into()));
     while let Some(r) = cur {
         ranges.push(r);
-        cur = extend_selection(file.syntax(), r);
+        cur = extend_selection(&file, r);
     }
     let ranges = ranges
         .iter()
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index bf0727dde2..4665a336ab 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -1,11 +1,16 @@
 use ra_syntax::{
     algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
-    Direction,
+    Direction, SourceFileNode,
     SyntaxKind::*,
     SyntaxNodeRef, TextRange, TextUnit,
 };
 
-pub fn extend_selection(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> {
+pub fn extend_selection(file: &SourceFileNode, range: TextRange) -> Option<TextRange> {
+    let syntax = file.syntax();
+    extend(syntax.borrowed(), range)
+}
+
+pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> {
     if range.is_empty() {
         let offset = range.start();
         let mut leaves = find_leaf_at_offset(root, offset);
@@ -121,7 +126,6 @@ fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use ra_syntax::SourceFileNode;
     use test_utils::extract_offset;
 
     fn do_check(before: &str, afters: &[&str]) {
@@ -129,7 +133,7 @@ mod tests {
         let file = SourceFileNode::parse(&before);
         let mut range = TextRange::offset_len(cursor, 0.into());
         for &after in afters {
-            range = extend_selection(file.syntax(), range).unwrap();
+            range = extend_selection(&file, range).unwrap();
             let actual = &before[range];
             assert_eq!(after, actual);
         }
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index b03f9ea541..a65637d52e 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -22,7 +22,7 @@ pub use self::{
 use ra_text_edit::{TextEdit, TextEditBuilder};
 use ra_syntax::{
     algo::find_leaf_at_offset,
-    ast::{self, AstNode},
+    ast::{self, AstNode, NameOwner},
     SourceFileNode,
     SyntaxKind::{self, *},
     SyntaxNodeRef, TextRange, TextUnit, Direction,
@@ -49,6 +49,18 @@ pub struct Diagnostic {
     pub fix: Option<LocalEdit>,
 }
 
+#[derive(Debug)]
+pub struct Runnable {
+    pub range: TextRange,
+    pub kind: RunnableKind,
+}
+
+#[derive(Debug)]
+pub enum RunnableKind {
+    Test { name: String },
+    Bin,
+}
+
 pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> {
     const BRACES: &[SyntaxKind] = &[
         L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
@@ -67,11 +79,11 @@ pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUni
     Some(matching_node.range().start())
 }
 
-pub fn highlight(root: SyntaxNodeRef) -> Vec<HighlightedRange> {
+pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> {
     // Visited nodes to handle highlighting priorities
     let mut highlighted = FxHashSet::default();
     let mut res = Vec::new();
-    for node in root.descendants() {
+    for node in file.syntax().descendants() {
         if highlighted.contains(&node) {
             continue;
         }
@@ -121,6 +133,29 @@ pub fn syntax_tree(file: &SourceFileNode) -> String {
     ::ra_syntax::utils::dump_tree(file.syntax())
 }
 
+pub fn runnables(file: &SourceFileNode) -> Vec<Runnable> {
+    file.syntax()
+        .descendants()
+        .filter_map(ast::FnDef::cast)
+        .filter_map(|f| {
+            let name = f.name()?.text();
+            let kind = if name == "main" {
+                RunnableKind::Bin
+            } else if f.has_atom_attr("test") {
+                RunnableKind::Test {
+                    name: name.to_string(),
+                }
+            } else {
+                return None;
+            };
+            Some(Runnable {
+                range: f.syntax().range(),
+                kind,
+            })
+        })
+        .collect()
+}
+
 pub fn find_node_at_offset<'a, N: AstNode<'a>>(
     syntax: SyntaxNodeRef<'a>,
     offset: TextUnit,
@@ -143,7 +178,7 @@ fn main() {}
     println!("Hello, {}!", 92);
 "#,
         );
-        let hls = highlight(file.syntax());
+        let hls = highlight(&file);
         assert_eq_dbg(
             r#"[HighlightedRange { range: [1; 11), tag: "comment" },
                 HighlightedRange { range: [12; 14), tag: "keyword" },
@@ -155,6 +190,29 @@ fn main() {}
         );
     }
 
+    #[test]
+    fn test_runnables() {
+        let file = SourceFileNode::parse(
+            r#"
+fn main() {}
+
+#[test]
+fn test_foo() {}
+
+#[test]
+#[ignore]
+fn test_foo() {}
+"#,
+        );
+        let runnables = runnables(&file);
+        assert_eq_dbg(
+            r#"[Runnable { range: [1; 13), kind: Bin },
+                Runnable { range: [15; 39), kind: Test { name: "test_foo" } },
+                Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#,
+            &runnables,
+        )
+    }
+
     #[test]
     fn test_matching_brace() {
         fn do_check(before: &str, after: &str) {
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index 87e30191fb..24c3469847 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -75,11 +75,6 @@ impl Module {
         Some(Crate::new(crate_id))
     }
 
-    /// Returns the all modulkes on the way to the root.
-    pub fn path_to_root(&self) -> Vec<Module> {
-        generate(Some(self.clone()), move |it| it.parent()).collect::<Vec<Module>>()
-    }
-
     /// The root of the tree this module is part of
     pub fn crate_root(&self) -> Module {
         let root_id = self.module_id.crate_root(&self.tree);
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index a74f9f27b6..8d508a3ba5 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -28,7 +28,7 @@ pub fn server_capabilities() -> ServerCapabilities {
         type_definition_provider: None,
         implementation_provider: None,
         references_provider: Some(true),
-        document_highlight_provider: Some(true),
+        document_highlight_provider: None,
         document_symbol_provider: Some(true),
         workspace_symbol_provider: Some(true),
         code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 618486250d..0d6e627273 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -82,6 +82,7 @@ impl Conv for CompletionItem {
             InsertText::Snippet { text } => {
                 res.insert_text = Some(text);
                 res.insert_text_format = Some(InsertTextFormat::Snippet);
+                res.kind = Some(languageserver_types::CompletionItemKind::Keyword);
             }
         }
         res
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 06dd373c02..d425b6733a 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -300,7 +300,6 @@ fn on_request(
         .on::<req::Rename>(handlers::handle_rename)?
         .on::<req::References>(handlers::handle_references)?
         .on::<req::Formatting>(handlers::handle_formatting)?
-        .on::<req::DocumentHighlightRequest>(handlers::handle_document_highlight)?
         .finish();
     match req {
         Ok(id) => {
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 11825d74e4..3b7a14a5c0 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -6,8 +6,9 @@ use languageserver_types::{
     DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
     FoldingRangeParams, Location, MarkupContent, MarkupKind, MarkedString, Position,
     PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
-    Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover,
-    HoverContents, DocumentFormattingParams, DocumentHighlight,
+    Range,
+    WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, HoverContents,
+    DocumentFormattingParams,
 };
 use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity};
 use ra_syntax::{TextUnit, text_utils::intersect};
@@ -256,7 +257,6 @@ pub fn handle_runnables(
             range: runnable.range.conv_with(&line_index),
             label: match &runnable.kind {
                 RunnableKind::Test { name } => format!("test {}", name),
-                RunnableKind::TestMod { path } => format!("test-mod {}", path),
                 RunnableKind::Bin => "run binary".to_string(),
             },
             bin: "cargo".to_string(),
@@ -308,15 +308,6 @@ pub fn handle_runnables(
                 res.push(name.to_string());
                 res.push("--nocapture".to_string());
             }
-            RunnableKind::TestMod { path } => {
-                res.push("test".to_string());
-                if let Some(spec) = spec {
-                    spec.push_to(&mut res);
-                }
-                res.push("--".to_string());
-                res.push(path.to_string());
-                res.push("--nocapture".to_string());
-            }
             RunnableKind::Bin => {
                 res.push("run".to_string());
                 if let Some(spec) = spec {
@@ -677,27 +668,6 @@ pub fn handle_code_action(
     Ok(Some(CodeActionResponse::Commands(res)))
 }
 
-pub fn handle_document_highlight(
-    world: ServerWorld,
-    params: req::TextDocumentPositionParams,
-) -> Result<Option<Vec<DocumentHighlight>>> {
-    let file_id = params.text_document.try_conv_with(&world)?;
-    let line_index = world.analysis().file_line_index(file_id);
-
-    let refs = world
-        .analysis()
-        .find_all_refs(params.try_conv_with(&world)?)?;
-
-    Ok(Some(
-        refs.into_iter()
-            .map(|r| DocumentHighlight {
-                range: r.1.conv_with(&line_index),
-                kind: None,
-            })
-            .collect(),
-    ))
-}
-
 pub fn publish_diagnostics(
     world: &ServerWorld,
     file_id: FileId,
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs
index 10d3d1dec4..1d6fe88375 100644
--- a/crates/ra_syntax/src/validation/char.rs
+++ b/crates/ra_syntax/src/validation/char.rs
@@ -89,12 +89,17 @@ pub(super) fn is_ascii_escape(code: char) -> bool {
 
 fn validate_ascii_code_escape(text: &str, range: TextRange, errors: &mut Vec<SyntaxError>) {
     // An AsciiCodeEscape has 4 chars, example: `\xDD`
-    if text.len() < 4 {
+    if !text.is_ascii() {
+        // TODO: Give a more precise error message (say what the invalid character was)
+        errors.push(SyntaxError::new(AsciiCodeEscapeOutOfRange, range));
+    } else if text.chars().count() < 4 {
         errors.push(SyntaxError::new(TooShortAsciiCodeEscape, range));
     } else {
-        assert!(
-            text.chars().count() == 4,
-            "AsciiCodeEscape cannot be longer than 4 chars"
+        assert_eq!(
+            text.chars().count(),
+            4,
+            "AsciiCodeEscape cannot be longer than 4 chars, but text '{}' is",
+            text,
         );
 
         match u8::from_str_radix(&text[2..], 16) {
diff --git a/crates/tools/src/lib.rs b/crates/tools/src/lib.rs
index fa619af333..e5b32c25ce 100644
--- a/crates/tools/src/lib.rs
+++ b/crates/tools/src/lib.rs
@@ -139,20 +139,3 @@ pub fn install_format_hook() -> Result<()> {
     }
     Ok(())
 }
-
-pub fn run_fuzzer() -> Result<()> {
-    match Command::new("cargo")
-        .args(&["fuzz", "--help"])
-        .stderr(Stdio::null())
-        .stdout(Stdio::null())
-        .status()
-    {
-        Ok(status) if status.success() => (),
-        _ => run("cargo install cargo-fuzz", ".")?,
-    };
-
-    run(
-        "rustup run nightly -- cargo fuzz run parser",
-        "./crates/ra_syntax",
-    )
-}
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs
index 9d73d57c4a..7edf8f52d8 100644
--- a/crates/tools/src/main.rs
+++ b/crates/tools/src/main.rs
@@ -7,10 +7,7 @@ use std::{
 use clap::{App, Arg, SubCommand};
 use failure::bail;
 
-use tools::{
-    collect_tests, generate,install_format_hook, run, run_rustfmt,
-    Mode, Overwrite, Result, Test, Verify, project_root, run_fuzzer
-};
+use tools::{collect_tests, generate, install_format_hook, run, run_rustfmt, Mode, Overwrite, Result, Test, Verify, project_root};
 
 const GRAMMAR_DIR: &str = "crates/ra_syntax/src/grammar";
 const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/tests/data/parser/inline/ok";
@@ -30,7 +27,6 @@ fn main() -> Result<()> {
         .subcommand(SubCommand::with_name("install-code"))
         .subcommand(SubCommand::with_name("format"))
         .subcommand(SubCommand::with_name("format-hook"))
-        .subcommand(SubCommand::with_name("fuzz-tests"))
         .get_matches();
     let mode = if matches.is_present("verify") {
         Verify
@@ -46,7 +42,6 @@ fn main() -> Result<()> {
         "gen-syntax" => generate(Overwrite)?,
         "format" => run_rustfmt(mode)?,
         "format-hook" => install_format_hook()?,
-        "fuzz-tests" => run_fuzzer()?,
         _ => unreachable!(),
     }
     Ok(())


Test patch:
diff --git a/crates/ra_analysis/tests/runnables.rs b/crates/ra_analysis/tests/runnables.rs
deleted file mode 100644
index 9e5342c462..0000000000
--- a/crates/ra_analysis/tests/runnables.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-extern crate ra_analysis;
-extern crate ra_editor;
-extern crate ra_syntax;
-extern crate relative_path;
-extern crate rustc_hash;
-extern crate test_utils;
-
-use test_utils::assert_eq_dbg;
-
-use ra_analysis::{
-    mock_analysis::{analysis_and_position},
-};
-
-#[test]
-fn test_runnables() {
-    let (analysis, pos) = analysis_and_position(
-        r#"
-        //- /lib.rs
-        <|> //empty
-        fn main() {}
-
-        #[test]
-        fn test_foo() {}
-
-        #[test]
-        #[ignore]
-        fn test_foo() {}
-        "#,
-    );
-    let runnables = analysis.runnables(pos.file_id).unwrap();
-    assert_eq_dbg(
-        r#"[Runnable { range: [1; 21), kind: Bin },
-                Runnable { range: [22; 46), kind: Test { name: "test_foo" } },
-                Runnable { range: [47; 81), kind: Test { name: "test_foo" } }]"#,
-        &runnables,
-    )
-}
-
-#[test]
-fn test_runnables_module() {
-    let (analysis, pos) = analysis_and_position(
-        r#"
-        //- /lib.rs
-        <|> //empty
-        mod test_mod {
-            #[test]
-            fn test_foo1() {}
-        }
-        "#,
-    );
-    let runnables = analysis.runnables(pos.file_id).unwrap();
-    assert_eq_dbg(
-        r#"[Runnable { range: [1; 59), kind: TestMod { path: "test_mod" } },
-                Runnable { range: [28; 57), kind: Test { name: "test_foo1" } }]"#,
-        &runnables,
-    )
-}
-
-#[test]
-fn test_runnables_one_depth_layer_module() {
-    let (analysis, pos) = analysis_and_position(
-        r#"
-        //- /lib.rs
-        <|> //empty
-        mod foo {
-            mod test_mod {
-                #[test]
-                fn test_foo1() {}
-            }
-        }
-        "#,
-    );
-    let runnables = analysis.runnables(pos.file_id).unwrap();
-    assert_eq_dbg(
-        r#"[Runnable { range: [23; 85), kind: TestMod { path: "foo::test_mod" } },
-                Runnable { range: [46; 79), kind: Test { name: "test_foo1" } }]"#,
-        &runnables,
-    )
-}
-
-#[test]
-fn test_runnables_multiple_depth_module() {
-    let (analysis, pos) = analysis_and_position(
-        r#"
-        //- /lib.rs
-        <|> //empty
-        mod foo {
-            mod bar {
-                mod test_mod {
-                    #[test]
-                    fn test_foo1() {}
-                }
-            }
-        }
-        "#,
-    );
-    let runnables = analysis.runnables(pos.file_id).unwrap();
-    assert_eq_dbg(
-        r#"[Runnable { range: [41; 115), kind: TestMod { path: "foo::bar::test_mod" } },
-                Runnable { range: [68; 105), kind: Test { name: "test_foo1" } }]"#,
-        &runnables,
-    )
-}
-
-#[test]
-fn test_runnables_no_test_function_in_module() {
-    let (analysis, pos) = analysis_and_position(
-        r#"
-        //- /lib.rs
-        <|> //empty
-        mod test_mod {
-            fn foo1() {}
-        }
-        "#,
-    );
-    let runnables = analysis.runnables(pos.file_id).unwrap();
-    assert_eq_dbg(r#"[]"#, &runnables)
-}
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index b61ead752c..a314fbc40a 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -131,56 +131,6 @@ fn test_resolve_parent_module_for_inline() {
     );
 }
 
-#[test]
-fn test_path_one_layer() {
-    let (analysis, pos) = analysis_and_position(
-        "
-        //- /lib.rs
-        mod foo;
-        //- /foo/mod.rs
-        mod bla;
-        //- /foo/bla.rs
-        <|> //empty
-    ",
-    );
-    let symbols = analysis.module_path(pos).unwrap().unwrap();
-    assert_eq!("foo::bla", &symbols);
-}
-
-#[test]
-fn test_path_two_layer() {
-    let (analysis, pos) = analysis_and_position(
-        "
-        //- /lib.rs
-        mod foo;
-        //- /foo/mod.rs
-        mod bla;
-        //- /foo/bla/mod.rs
-        mod more;
-        //- /foo/bla/more.rs
-        <|> //empty
-    ",
-    );
-    let symbols = analysis.module_path(pos).unwrap().unwrap();
-    assert_eq!("foo::bla::more", &symbols);
-}
-
-#[test]
-fn test_path_in_file_mod() {
-    let (analysis, pos) = analysis_and_position(
-        "
-        //- /lib.rs
-        mod foo;
-        //- /foo.rs
-        mod bar {
-            <|> //empty
-        }
-    ",
-    );
-    let symbols = analysis.module_path(pos).unwrap().unwrap();
-    assert_eq!("foo::bar", &symbols);
-}
-
 #[test]
 fn test_resolve_crate_root() {
     let mock = MockAnalysis::with_files(
diff --git a/crates/ra_syntax/tests/data/parser/fuzz-failures/0003.rs b/crates/ra_syntax/tests/data/parser/fuzz-failures/0003.rs
new file mode 100644
index 0000000000..0f59c47226
--- /dev/null
+++ b/crates/ra_syntax/tests/data/parser/fuzz-failures/0003.rs
@@ -0,0 +1,1 @@
+if'\xɿ
\ No newline at end of file