From 3188c1451a6f1237859dcb813debef9fa537195c Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 10 Nov 2019 13:59:39 -0500 Subject: Hover for builtins --- crates/ra_ide_api/src/hover.rs | 50 ++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index ba328efa1..244c65814 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir::{Adt, HasSource, HirDisplay}; +use hir::{Adt, BuiltinType, HasSource, HirDisplay}; use ra_db::SourceDatabase; use ra_syntax::{ algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, @@ -117,27 +117,27 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option from_def_source(db, it), hir::AssocItem::TypeAlias(it) => from_def_source(db, it), }), - Some(Def(it)) => { - match it { - hir::ModuleDef::Module(it) => { - if let hir::ModuleSource::Module(it) = it.definition_source(db).ast { - res.extend(hover_text(it.doc_comment_text(), it.short_label())) - } + Some(Def(it)) => match it { + hir::ModuleDef::Module(it) => { + if let hir::ModuleSource::Module(it) = it.definition_source(db).ast { + res.extend(hover_text(it.doc_comment_text(), it.short_label())) } - hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)), - hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::BuiltinType(_) => { - // FIXME: hover for builtin Type ? + } + hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)), + hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)), + hir::ModuleDef::BuiltinType(it) => { + if let Some(b) = BuiltinType::ALL.iter().find(|(_, ty)| *ty == it) { + res.extend(Some(b.0.to_string())) } } - } + }, Some(SelfType(ty)) => { if let Some((adt_def, _)) = ty.as_adt() { res.extend(match adt_def { @@ -722,4 +722,16 @@ fn func(foo: i32) { if true { <|>foo; }; } assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); assert_eq!(hover.info.is_exact(), true); } + + #[test] + fn test_hover_tuple_field() { + let (analysis, position) = single_file_with_position( + " + struct TS(String, i32<|>); + ", + ); + let hover = analysis.hover(position).unwrap().unwrap(); + assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); + assert_eq!(hover.info.is_exact(), true); + } } -- cgit v1.2.3 From c46768d13dd34bbe878cc62eca4af873ffbb7c22 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 10 Nov 2019 11:03:24 +0800 Subject: Add basic bultin macro infrastructure --- crates/ra_hir/src/code_model/src.rs | 11 +++-- crates/ra_hir_def/src/nameres/collector.rs | 28 +++++++++++-- crates/ra_hir_def/src/nameres/raw.rs | 7 +++- crates/ra_hir_expand/src/builtin_macro.rs | 26 ++++++++++++ crates/ra_hir_expand/src/db.rs | 66 ++++++++++++++++++++++-------- crates/ra_hir_expand/src/hygiene.rs | 7 +++- crates/ra_hir_expand/src/lib.rs | 29 +++++++++++-- crates/ra_hir_expand/src/name.rs | 3 ++ 8 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 crates/ra_hir_expand/src/builtin_macro.rs diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 6d116ee75..c4e62f799 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -6,8 +6,8 @@ use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, ids::AstItemDef, - Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module, - ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, + Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, + MacroDefId, Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; pub use hir_expand::Source; @@ -140,10 +140,15 @@ impl HasSource for TypeAlias { self.id.source(db) } } + impl HasSource for MacroDef { type Ast = ast::MacroCall; fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - Source { file_id: self.id.ast_id.file_id(), ast: self.id.ast_id.to_node(db) } + let ast_id = match self.id { + MacroDefId::DeclarativeMacro(it) => it.ast_id, + MacroDefId::BuiltinMacro(it) => it.ast_id, + }; + Source { file_id: ast_id.file_id(), ast: ast_id.to_node(db) } } } diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index aacd50df8..5f18e9de3 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -1,8 +1,9 @@ //! FIXME: write short doc here use hir_expand::{ + builtin_macro::find_builtin_macro, name::{self, AsName, Name}, - HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind, + DeclarativeMacro, HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind, }; use ra_cfg::CfgOptions; use ra_db::{CrateId, FileId}; @@ -688,11 +689,32 @@ where fn collect_macro(&mut self, mac: &raw::MacroData) { let ast_id = AstId::new(self.file_id, mac.ast_id); + // Case 0: builtin macros + if mac.builtin { + if let Some(name) = &mac.name { + let krate = self.def_collector.def_map.krate; + if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { + self.def_collector.define_macro( + self.module_id, + name.clone(), + macro_id, + mac.export, + ); + return; + } + } + } + // 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 }; - self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); + let macro_id = DeclarativeMacro { ast_id, krate: self.def_collector.def_map.krate }; + self.def_collector.define_macro( + self.module_id, + name.clone(), + MacroDefId::DeclarativeMacro(macro_id), + mac.export, + ); } return; } diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 369376f30..f52002bc0 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -200,6 +200,7 @@ pub(super) struct MacroData { pub(super) path: Path, pub(super) name: Option, pub(super) export: bool, + pub(super) builtin: bool, } struct RawItemsCollector { @@ -367,7 +368,11 @@ impl RawItemsCollector { // FIXME: cfg_attr let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); - let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); + // FIXME: cfg_attr + let builtin = + m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro"); + + let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin }); self.push_item(current_module, attrs, RawItemKind::Macro(m)); } diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs new file mode 100644 index 000000000..dca2f17ef --- /dev/null +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -0,0 +1,26 @@ +//! Builtin macro +use crate::{ast, name, AstId, BuiltinMacro, CrateId, MacroDefId}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum BuiltinExpander { + Line +} + +impl BuiltinExpander { + pub fn expand(&self, _tt: &tt::Subtree) -> Result { + Err(mbe::ExpandError::UnexpectedToken) + } +} + +pub fn find_builtin_macro( + ident: &name::Name, + krate: CrateId, + ast_id: AstId, +) -> Option { + // FIXME: Better registering method + if ident == &name::LINE { + Some(MacroDefId::BuiltinMacro(BuiltinMacro { expander: BuiltinExpander::Line, krate, ast_id })) + } else { + None + } +} diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index b4dafe1d8..343c9e6bf 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -9,10 +9,37 @@ use ra_prof::profile; use ra_syntax::{AstNode, Parse, SyntaxNode}; use crate::{ - ast_id_map::AstIdMap, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, - MacroFile, MacroFileKind, + ast_id_map::AstIdMap, BuiltinExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, + MacroDefId, MacroFile, MacroFileKind, }; +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum TokenExpander { + MacroRules(mbe::MacroRules), + Builtin(BuiltinExpander), +} + +impl TokenExpander { + pub fn expand( + &self, + db: &dyn AstDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> Result { + match self { + TokenExpander::MacroRules(it) => it.expand(tt), + TokenExpander::Builtin(it) => it.expand(tt), + } + } + + pub fn shift(&self) -> u32 { + match self { + TokenExpander::MacroRules(it) => it.shift(), + TokenExpander::Builtin(_) => 0, + } + } +} + // FIXME: rename to ExpandDatabase #[salsa::query_group(AstDatabaseStorage)] pub trait AstDatabase: SourceDatabase { @@ -24,7 +51,7 @@ pub trait AstDatabase: SourceDatabase { #[salsa::interned] fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId; fn macro_arg(&self, id: MacroCallId) -> Option>; - fn macro_def(&self, id: MacroDefId) -> Option>; + fn macro_def(&self, id: MacroDefId) -> Option>; fn parse_macro( &self, macro_file: MacroFile, @@ -41,18 +68,25 @@ pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc Option> { - let macro_call = id.ast_id.to_node(db); - let arg = macro_call.token_tree()?; - let (tt, tmap) = 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, tmap))) +) -> Option> { + match id { + MacroDefId::DeclarativeMacro(it) => { + let macro_call = it.ast_id.to_node(db); + let arg = macro_call.token_tree()?; + let (tt, tmap) = 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((TokenExpander::MacroRules(rules), tmap))) + } + MacroDefId::BuiltinMacro(it) => { + Some(Arc::new((TokenExpander::Builtin(it.expander.clone()), mbe::TokenMap::default()))) + } + } } pub(crate) fn macro_arg( @@ -74,7 +108,7 @@ pub(crate) fn macro_expand( 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.0.expand(¯o_arg.0).map_err(|err| format!("{:?}", err))?; + let tt = macro_rules.0.expand(db, id, ¯o_arg.0).map_err(|err| format!("{:?}", err))?; // Set a hard limit for the expanded tt let count = tt.count(); if count > 65536 { diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 77428ec99..6b682d3ab 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -9,7 +9,7 @@ use crate::{ db::AstDatabase, either::Either, name::{AsName, Name}, - HirFileId, HirFileIdRepr, + HirFileId, HirFileIdRepr, MacroDefId, }; #[derive(Debug)] @@ -24,7 +24,10 @@ impl Hygiene { HirFileIdRepr::FileId(_) => None, HirFileIdRepr::MacroFile(macro_file) => { let loc = db.lookup_intern_macro(macro_file.macro_call_id); - Some(loc.def.krate) + match loc.def { + MacroDefId::DeclarativeMacro(it) => Some(it.krate), + MacroDefId::BuiltinMacro(_) => None, + } } }; Hygiene { def_crate } diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 151d1d785..6b71738ee 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -10,6 +10,7 @@ pub mod either; pub mod name; pub mod hygiene; pub mod diagnostics; +pub mod builtin_macro; use std::hash::{Hash, Hasher}; use std::sync::Arc; @@ -21,6 +22,7 @@ use ra_syntax::{ }; use crate::ast_id_map::FileAstId; +use crate::builtin_macro::BuiltinExpander; /// 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 @@ -75,9 +77,15 @@ impl HirFileId { HirFileIdRepr::MacroFile(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); + // FIXME: Do we support expansion information in builtin macro? + let macro_decl = match loc.def { + MacroDefId::DeclarativeMacro(it) => (it), + MacroDefId::BuiltinMacro(_) => return None, + }; + let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); let def_start = - loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); + macro_decl.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); let macro_def = db.macro_def(loc.def)?; let shift = macro_def.0.shift(); @@ -85,7 +93,7 @@ impl HirFileId { let macro_arg = db.macro_arg(macro_file.macro_call_id)?; let arg_start = (loc.ast_id.file_id, arg_start); - let def_start = (loc.def.ast_id.file_id, def_start); + let def_start = (macro_decl.ast_id.file_id, def_start); Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift }) } @@ -119,9 +127,22 @@ impl salsa::InternKey for MacroCallId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct MacroDefId { +pub enum MacroDefId { + DeclarativeMacro(DeclarativeMacro), + BuiltinMacro(BuiltinMacro), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DeclarativeMacro { + pub krate: CrateId, + pub ast_id: AstId, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct BuiltinMacro { pub krate: CrateId, pub ast_id: AstId, + pub expander: BuiltinExpander, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -144,7 +165,7 @@ pub struct ExpansionInfo { pub(crate) def_start: (HirFileId, TextUnit), pub(crate) shift: u32, - pub(crate) macro_def: Arc<(mbe::MacroRules, mbe::TokenMap)>, + pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, pub(crate) exp_map: Arc, } diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 720896ee8..1bf17d12b 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs @@ -140,3 +140,6 @@ 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"); + +// Builtin Macros +pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); -- cgit v1.2.3 From 1637a8a59071d8c7976ffc8d04edc5b7f54ae40b Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 11 Nov 2019 14:14:39 +0800 Subject: Add quote macro --- crates/ra_hir_expand/src/lib.rs | 1 + crates/ra_hir_expand/src/quote.rs | 261 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 crates/ra_hir_expand/src/quote.rs diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 6b71738ee..21d666f13 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -11,6 +11,7 @@ pub mod name; pub mod hygiene; pub mod diagnostics; pub mod builtin_macro; +pub mod quote; use std::hash::{Hash, Hasher}; use std::sync::Arc; diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs new file mode 100644 index 000000000..9cd17f0e3 --- /dev/null +++ b/crates/ra_hir_expand/src/quote.rs @@ -0,0 +1,261 @@ +//! A simplified version of quote-crate like quasi quote macro + +// A helper macro quote macro +// FIXME: +// 1. Not all puncts are handled +// 2. #()* pattern repetition not supported now +// * But we can do it manually, see `test_quote_derive_copy_hack` +#[doc(hidden)] +#[macro_export] +macro_rules! __quote { + () => { + Vec::::new() + }; + + ( @SUBTREE $delim:ident $($tt:tt)* ) => { + { + let children = $crate::__quote!($($tt)*); + let subtree = tt::Subtree { + delimiter: tt::Delimiter::$delim, + token_trees: $crate::quote::IntoTt::to_tokens(children), + }; + subtree + } + }; + + ( @PUNCT $first:literal ) => { + { + vec![ + tt::Leaf::Punct(tt::Punct { + char: $first, + spacing: tt::Spacing::Alone, + }).into() + ] + } + }; + + ( @PUNCT $first:literal, $sec:literal ) => { + { + vec![ + tt::Leaf::Punct(tt::Punct { + char: $first, + spacing: tt::Spacing::Joint, + }).into(), + tt::Leaf::Punct(tt::Punct { + char: $sec, + spacing: tt::Spacing::Alone, + }).into() + ] + } + }; + + // hash variable + ( # $first:ident $($tail:tt)* ) => { + { + let token = $crate::quote::ToTokenTree::to_token($first); + let mut tokens = vec![token.into()]; + let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); + tokens.append(&mut tail_tokens); + tokens + } + }; + + // Brace + ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; + // Bracket + ( [ $($tt:tt)* ] ) => { $crate::__quote!(@SUBTREE Bracket $($tt)*) }; + // Parenthesis + ( ( $($tt:tt)* ) ) => { $crate::__quote!(@SUBTREE Parenthesis $($tt)*) }; + + // Literal + ( $tt:literal ) => { vec![$crate::quote::ToTokenTree::to_token($tt).into()] }; + // Ident + ( $tt:ident ) => { + vec![ { + tt::Leaf::Ident(tt::Ident { + text: stringify!($tt).into(), + id: tt::TokenId::unspecified(), + }).into() + }] + }; + + // Puncts + // FIXME: Not all puncts are handled + ( -> ) => {$crate::__quote!(@PUNCT '-', '>')}; + ( & ) => {$crate::__quote!(@PUNCT '&')}; + ( , ) => {$crate::__quote!(@PUNCT ',')}; + ( : ) => {$crate::__quote!(@PUNCT ':')}; + ( . ) => {$crate::__quote!(@PUNCT '.')}; + + ( $first:tt $($tail:tt)+ ) => { + { + let mut tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($first)); + let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*)); + + tokens.append(&mut tail_tokens); + tokens + } + }; +} + +/// FIXME: +/// It probably should implement in proc-macro +#[macro_export] +macro_rules! quote { + ( $($tt:tt)* ) => { + $crate::quote::IntoTt::to_subtree($crate::__quote!($($tt)*)) + } +} + +pub(crate) trait IntoTt { + fn to_subtree(self) -> tt::Subtree; + fn to_tokens(self) -> Vec; +} + +impl IntoTt for Vec { + fn to_subtree(self) -> tt::Subtree { + tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self } + } + + fn to_tokens(self) -> Vec { + self + } +} + +impl IntoTt for tt::Subtree { + fn to_subtree(self) -> tt::Subtree { + self + } + + fn to_tokens(self) -> Vec { + vec![tt::TokenTree::Subtree(self)] + } +} + +pub(crate) trait ToTokenTree { + fn to_token(self) -> tt::TokenTree; +} + +impl ToTokenTree for tt::TokenTree { + fn to_token(self) -> tt::TokenTree { + self + } +} + +impl ToTokenTree for tt::Subtree { + fn to_token(self) -> tt::TokenTree { + self.into() + } +} + +macro_rules! impl_to_to_tokentrees { + ($($ty:ty => $this:ident $im:block);*) => { + $( + impl ToTokenTree for $ty { + fn to_token($this) -> tt::TokenTree { + let leaf: tt::Leaf = $im.into(); + leaf.into() + } + } + + impl ToTokenTree for &$ty { + fn to_token($this) -> tt::TokenTree { + let leaf: tt::Leaf = $im.clone().into(); + leaf.into() + } + } + )* + } +} + +impl_to_to_tokentrees! { + u32 => self { tt::Literal{text: self.to_string().into()} }; + usize => self { tt::Literal{text: self.to_string().into()}}; + i32 => self { tt::Literal{text: self.to_string().into()}}; + &str => self { tt::Literal{text: self.to_string().into()}}; + String => self { tt::Literal{text: self.into()}}; + tt::Leaf => self { self }; + tt::Literal => self { self }; + tt::Ident => self { self }; + tt::Punct => self { self } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_quote_delimiters() { + assert_eq!(quote!({}).to_string(), "{}"); + assert_eq!(quote!(()).to_string(), "()"); + assert_eq!(quote!([]).to_string(), "[]"); + } + + #[test] + fn test_quote_idents() { + assert_eq!(quote!(32).to_string(), "32"); + assert_eq!(quote!(struct).to_string(), "struct"); + } + + #[test] + fn test_quote_hash_simple_literal() { + let a = 20; + assert_eq!(quote!(#a).to_string(), "20"); + let s: String = "hello".into(); + assert_eq!(quote!(#s).to_string(), "hello"); + } + + fn mk_ident(name: &str) -> tt::Ident { + tt::Ident { text: name.into(), id: tt::TokenId::unspecified() } + } + + #[test] + fn test_quote_hash_token_tree() { + let a = mk_ident("hello"); + + let quoted = quote!(#a); + assert_eq!(quoted.to_string(), "hello"); + let t = format!("{:?}", quoted); + assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }"); + } + + #[test] + fn test_quote_simple_derive_copy() { + let name = mk_ident("Foo"); + + let quoted = quote! { + impl Clone for #name { + fn clone(&self) -> Self { + Self {} + } + } + }; + + assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {}}}"); + } + + #[test] + fn test_quote_derive_copy_hack() { + // Assume the given struct is: + // struct Foo { + // name: String, + // id: u32, + // } + let struct_name = mk_ident("Foo"); + let fields = [mk_ident("name"), mk_ident("id")]; + let fields = fields + .into_iter() + .map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()) + .flatten(); + + let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; + + let quoted = quote! { + impl Clone for #struct_name { + fn clone(&self) -> Self { + Self #list + } + } + }; + + assert_eq!(quoted.to_string(), "impl Clone for Foo {fn clone (& self) -> Self {Self {name : self . name . clone () , id : self . id . clone () ,}}}"); + } +} -- cgit v1.2.3 From c4aa8b63bcea5faa23da56b679cafbdbad6892f1 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 11 Nov 2019 14:15:09 +0800 Subject: Add line macro and tests --- crates/ra_hir/src/ty/tests.rs | 19 +++++++++ crates/ra_hir_expand/src/builtin_macro.rs | 70 ++++++++++++++++++++++++++++--- crates/ra_hir_expand/src/db.rs | 2 +- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index e56b9356e..896bf2924 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -4810,3 +4810,22 @@ fn no_such_field_diagnostics() { "### ); } + +#[test] +fn infer_builtin_macros_line() { + assert_snapshot!( + infer(r#" +#[rustc_builtin_macro] +macro_rules! line {() => {}} + +fn main() { + let x = line!(); +} +"#), + @r###" + ![0; 1) '6': i32 + [64; 88) '{ ...!(); }': () + [74; 75) 'x': i32 + "### + ); +} diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index dca2f17ef..acb62da27 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -1,14 +1,28 @@ //! Builtin macro -use crate::{ast, name, AstId, BuiltinMacro, CrateId, MacroDefId}; +use crate::db::AstDatabase; +use crate::{ + ast::{self, AstNode}, + name, AstId, BuiltinMacro, CrateId, HirFileId, MacroCallId, MacroDefId, MacroFileKind, + TextUnit, +}; + +use crate::quote; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BuiltinExpander { - Line + Line, } impl BuiltinExpander { - pub fn expand(&self, _tt: &tt::Subtree) -> Result { - Err(mbe::ExpandError::UnexpectedToken) + pub fn expand( + &self, + db: &dyn AstDatabase, + id: MacroCallId, + tt: &tt::Subtree, + ) -> Result { + match self { + BuiltinExpander::Line => line_expand(db, id, tt), + } } } @@ -18,9 +32,53 @@ pub fn find_builtin_macro( ast_id: AstId, ) -> Option { // FIXME: Better registering method - if ident == &name::LINE { - Some(MacroDefId::BuiltinMacro(BuiltinMacro { expander: BuiltinExpander::Line, krate, ast_id })) + if ident == &name::LINE_MACRO { + Some(MacroDefId::BuiltinMacro(BuiltinMacro { + expander: BuiltinExpander::Line, + krate, + ast_id, + })) } else { None } } + +fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { + // FIXME: Use expansion info + let file_id = file.original_file(db); + let text = db.file_text(file_id); + let mut line_num = 1; + + // Count line end + for (i, c) in text.chars().enumerate() { + if i == pos.to_usize() { + break; + } + if c == '\n' { + line_num += 1; + } + } + + line_num +} + +fn line_expand( + db: &dyn AstDatabase, + id: MacroCallId, + _tt: &tt::Subtree, +) -> Result { + let loc = db.lookup_intern_macro(id); + let macro_call = loc.ast_id.to_node(db); + + let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; + let arg_start = arg.syntax().text_range().start(); + + let file = id.as_file(MacroFileKind::Expr); + let line_num = to_line_number(db, file, arg_start); + + let expanded = quote! { + #line_num + }; + + Ok(expanded) +} diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 343c9e6bf..009ff5312 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -28,7 +28,7 @@ impl TokenExpander { ) -> Result { match self { TokenExpander::MacroRules(it) => it.expand(tt), - TokenExpander::Builtin(it) => it.expand(tt), + TokenExpander::Builtin(it) => it.expand(db, id, tt), } } -- cgit v1.2.3 From ee876e78810e8b6ced726c8f2513e5b1a546ac37 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 09:20:18 +0300 Subject: Make primitive tys public --- crates/ra_hir/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 131f6c797..9dc8d139b 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -76,7 +76,11 @@ pub use crate::{ resolve::ScopeDef, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, ty::{ - display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, + display::HirDisplay, + primitive::{ + FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy, + }, + ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, }; -- cgit v1.2.3 From 9a04426617bdf2ff4599f571ff03e44e2e4054eb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 10:11:46 +0300 Subject: Disable debuginfo in dev builds Hopefully, this makes printf debugging faster! --- .travis.yml | 1 - Cargo.toml | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d66f72d8..af71a9cce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ matrix: script: - rustup component add rustfmt - rustup component add rust-src - - sed -i "s/debug = 1/debug = false/g" Cargo.toml - cargo test --no-run # let's measure compile time separately - cargo test env: diff --git a/Cargo.toml b/Cargo.toml index 97c02b40f..5c57020f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,9 @@ members = [ "crates/*", "xtask/" ] [profile.dev] -debug = 1 # only line info +# disabling debug info speeds up builds a bunch, +# and we don't rely on it for debugging that much. +debug = 0 [profile.release] incremental = true -- cgit v1.2.3 From 1860f9ab43acb77c9fdd7ca646ef65e9b008b932 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 11:26:57 +0300 Subject: Forbid visibility qualifiers in traits --- crates/ra_syntax/src/syntax_error.rs | 4 + crates/ra_syntax/src/validation.rs | 23 ++++- .../parser/err/0037_visibility_in_traits.rs | 6 ++ .../parser/err/0037_visibility_in_traits.txt | 99 ++++++++++++++++++++++ 4 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs create mode 100644 crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs index d6eca2ad7..1f60a7aab 100644 --- a/crates/ra_syntax/src/syntax_error.rs +++ b/crates/ra_syntax/src/syntax_error.rs @@ -82,6 +82,7 @@ pub enum SyntaxErrorKind { InvalidBlockAttr, InvalidMatchInnerAttr, InvalidTupleIndexFormat, + VisibilityNotAllowed, } impl fmt::Display for SyntaxErrorKind { @@ -99,6 +100,9 @@ impl fmt::Display for SyntaxErrorKind { } ParseError(msg) => write!(f, "{}", msg.0), EscapeError(err) => write!(f, "{}", err), + VisibilityNotAllowed => { + write!(f, "unnecessary visibility qualifier") + } } } } diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index ab4f15908..2d596763e 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs @@ -6,7 +6,7 @@ use rustc_lexer::unescape; use crate::{ ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, - SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, + SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, SyntaxNode, SyntaxToken, TextUnit, T, }; @@ -102,6 +102,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec { ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) }, ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, + ast::Visibility(it) => { validate_visibility(it, &mut errors) }, _ => (), } } @@ -206,3 +207,23 @@ fn validate_numeric_name(name_ref: Option, errors: &mut Vec) { + let parent = match vis.syntax().parent() { + Some(it) => it, + None => return, + }; + match parent.kind() { + FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (), + _ => return, + } + let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast) + { + Some(it) => it, + None => return, + }; + if impl_block.target_trait().is_some() { + errors + .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range())) + } +} diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs new file mode 100644 index 000000000..a43e7ef10 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rs @@ -0,0 +1,6 @@ +impl T for () { + fn foo() {} + pub fn bar() {} + pub(crate) type Baz = (); + pub(crate) const C: i32 = 92; +} diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt new file mode 100644 index 000000000..749c8cddb --- /dev/null +++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt @@ -0,0 +1,99 @@ +SOURCE_FILE@[0; 118) + IMPL_BLOCK@[0; 117) + IMPL_KW@[0; 4) "impl" + WHITESPACE@[4; 5) " " + PATH_TYPE@[5; 6) + PATH@[5; 6) + PATH_SEGMENT@[5; 6) + NAME_REF@[5; 6) + IDENT@[5; 6) "T" + WHITESPACE@[6; 7) " " + FOR_KW@[7; 10) "for" + WHITESPACE@[10; 11) " " + TUPLE_TYPE@[11; 13) + L_PAREN@[11; 12) "(" + R_PAREN@[12; 13) ")" + WHITESPACE@[13; 14) " " + ITEM_LIST@[14; 117) + L_CURLY@[14; 15) "{" + WHITESPACE@[15; 20) "\n " + FN_DEF@[20; 31) + FN_KW@[20; 22) "fn" + WHITESPACE@[22; 23) " " + NAME@[23; 26) + IDENT@[23; 26) "foo" + PARAM_LIST@[26; 28) + L_PAREN@[26; 27) "(" + R_PAREN@[27; 28) ")" + WHITESPACE@[28; 29) " " + BLOCK_EXPR@[29; 31) + BLOCK@[29; 31) + L_CURLY@[29; 30) "{" + R_CURLY@[30; 31) "}" + WHITESPACE@[31; 36) "\n " + FN_DEF@[36; 51) + VISIBILITY@[36; 39) + PUB_KW@[36; 39) "pub" + WHITESPACE@[39; 40) " " + FN_KW@[40; 42) "fn" + WHITESPACE@[42; 43) " " + NAME@[43; 46) + IDENT@[43; 46) "bar" + PARAM_LIST@[46; 48) + L_PAREN@[46; 47) "(" + R_PAREN@[47; 48) ")" + WHITESPACE@[48; 49) " " + BLOCK_EXPR@[49; 51) + BLOCK@[49; 51) + L_CURLY@[49; 50) "{" + R_CURLY@[50; 51) "}" + WHITESPACE@[51; 56) "\n " + TYPE_ALIAS_DEF@[56; 81) + VISIBILITY@[56; 66) + PUB_KW@[56; 59) "pub" + L_PAREN@[59; 60) "(" + CRATE_KW@[60; 65) "crate" + R_PAREN@[65; 66) ")" + WHITESPACE@[66; 67) " " + TYPE_KW@[67; 71) "type" + WHITESPACE@[71; 72) " " + NAME@[72; 75) + IDENT@[72; 75) "Baz" + WHITESPACE@[75; 76) " " + EQ@[76; 77) "=" + WHITESPACE@[77; 78) " " + TUPLE_TYPE@[78; 80) + L_PAREN@[78; 79) "(" + R_PAREN@[79; 80) ")" + SEMI@[80; 81) ";" + WHITESPACE@[81; 86) "\n " + CONST_DEF@[86; 115) + VISIBILITY@[86; 96) + PUB_KW@[86; 89) "pub" + L_PAREN@[89; 90) "(" + CRATE_KW@[90; 95) "crate" + R_PAREN@[95; 96) ")" + WHITESPACE@[96; 97) " " + CONST_KW@[97; 102) "const" + WHITESPACE@[102; 103) " " + NAME@[103; 104) + IDENT@[103; 104) "C" + COLON@[104; 105) ":" + WHITESPACE@[105; 106) " " + PATH_TYPE@[106; 109) + PATH@[106; 109) + PATH_SEGMENT@[106; 109) + NAME_REF@[106; 109) + IDENT@[106; 109) "i32" + WHITESPACE@[109; 110) " " + EQ@[110; 111) "=" + WHITESPACE@[111; 112) " " + LITERAL@[112; 114) + INT_NUMBER@[112; 114) "92" + SEMI@[114; 115) ";" + WHITESPACE@[115; 116) "\n" + R_CURLY@[116; 117) "}" + WHITESPACE@[117; 118) "\n" +error [36; 39): unnecessary visibility qualifier +error [56; 66): unnecessary visibility qualifier +error [86; 96): unnecessary visibility qualifier -- cgit v1.2.3 From 5bb92c2d1af5f3045617a665d4e5c676700eb3c1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 11:59:19 +0300 Subject: impl fmt::Display for BuiltinType --- crates/ra_hir_def/src/builtin_type.rs | 32 ++++++++++++++++++++++++++++++++ crates/ra_ide_api/src/hover.rs | 8 ++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs index 12929caa9..2ec0c83fe 100644 --- a/crates/ra_hir_def/src/builtin_type.rs +++ b/crates/ra_hir_def/src/builtin_type.rs @@ -3,6 +3,8 @@ //! A peculiarity of built-in types is that they are always available and are //! not associated with any particular crate. +use std::fmt; + use hir_expand::name::{self, Name}; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -61,3 +63,33 @@ impl BuiltinType { (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }), ]; } + +impl fmt::Display for BuiltinType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let type_name = match self { + BuiltinType::Char => "char", + BuiltinType::Bool => "bool", + BuiltinType::Str => "str", + BuiltinType::Int { signedness, bitness } => match (signedness, bitness) { + (Signedness::Signed, IntBitness::Xsize) => "isize", + (Signedness::Signed, IntBitness::X8) => "i8", + (Signedness::Signed, IntBitness::X16) => "i16", + (Signedness::Signed, IntBitness::X32) => "i32", + (Signedness::Signed, IntBitness::X64) => "i64", + (Signedness::Signed, IntBitness::X128) => "i128", + + (Signedness::Unsigned, IntBitness::Xsize) => "usize", + (Signedness::Unsigned, IntBitness::X8) => "u8", + (Signedness::Unsigned, IntBitness::X16) => "u16", + (Signedness::Unsigned, IntBitness::X32) => "u32", + (Signedness::Unsigned, IntBitness::X64) => "u64", + (Signedness::Unsigned, IntBitness::X128) => "u128", + }, + BuiltinType::Float { bitness } => match bitness { + FloatBitness::X32 => "f32", + FloatBitness::X64 => "f64", + }, + }; + f.write_str(type_name) + } +} diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 244c65814..cc41390b2 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir::{Adt, BuiltinType, HasSource, HirDisplay}; +use hir::{Adt, HasSource, HirDisplay}; use ra_db::SourceDatabase; use ra_syntax::{ algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, @@ -132,11 +132,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option res.extend(from_def_source(db, it)), hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)), hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)), - hir::ModuleDef::BuiltinType(it) => { - if let Some(b) = BuiltinType::ALL.iter().find(|(_, ty)| *ty == it) { - res.extend(Some(b.0.to_string())) - } - } + hir::ModuleDef::BuiltinType(it) => res.extend(Some(it.to_string())), }, Some(SelfType(ty)) => { if let Some((adt_def, _)) = ty.as_adt() { -- cgit v1.2.3 From 4deba88c33c470f084c531fa979fe5684d37f757 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 11:15:19 +0300 Subject: Introduce ToNav trait --- crates/ra_ide_api/src/display.rs | 2 +- crates/ra_ide_api/src/display/navigation_target.rs | 328 +++++++++++---------- crates/ra_ide_api/src/goto_definition.rs | 16 +- crates/ra_ide_api/src/goto_type_definition.rs | 4 +- crates/ra_ide_api/src/impls.rs | 11 +- crates/ra_ide_api/src/lib.rs | 4 +- crates/ra_ide_api/src/references.rs | 12 +- 7 files changed, 200 insertions(+), 177 deletions(-) diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index a980c56bc..30617412a 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs @@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature; pub use navigation_target::NavigationTarget; pub use structure::{file_structure, StructureNode}; -pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol}; +pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; pub(crate) use short_label::ShortLabel; pub(crate) fn function_label(node: &ast::FnDef) -> String { diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 1bf81e7d5..41d467564 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -29,19 +29,8 @@ pub struct NavigationTarget { docs: Option, } -fn find_range_from_node( - db: &RootDatabase, - src: hir::HirFileId, - node: &SyntaxNode, -) -> (FileId, TextRange) { - let text_range = node.text_range(); - let (file_id, text_range) = src - .expansion_info(db) - .and_then(|expansion_info| expansion_info.find_range(text_range)) - .unwrap_or((src, text_range)); - - // FIXME: handle recursive macro generated macro - (file_id.original_file(db), text_range) +pub(crate) trait ToNav { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget; } impl NavigationTarget { @@ -95,19 +84,6 @@ impl NavigationTarget { NavigationTarget::from_named(db, file_id.into(), pat, None, None) } - pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { - NavigationTarget { - file_id: symbol.file_id, - name: symbol.name.clone(), - kind: symbol.ptr.kind(), - full_range: symbol.ptr.range(), - focus_range: symbol.name_range, - container_name: symbol.container_name.clone(), - description: description_from_symbol(db, &symbol), - docs: docs_from_symbol(db, &symbol), - } - } - pub(crate) fn from_pat( db: &RootDatabase, file_id: FileId, @@ -136,39 +112,6 @@ impl NavigationTarget { } } - pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { - let src = module.definition_source(db); - let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); - match src.ast { - ModuleSource::SourceFile(node) => { - let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); - - NavigationTarget::from_syntax( - file_id, - name, - None, - text_range, - node.syntax(), - None, - None, - ) - } - ModuleSource::Module(node) => { - let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); - - NavigationTarget::from_syntax( - file_id, - name, - None, - text_range, - node.syntax(), - node.doc_comment_text(), - node.short_label(), - ) - } - } - } - pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); if let Some(src) = module.declaration_source(db) { @@ -183,55 +126,7 @@ impl NavigationTarget { src.ast.short_label(), ); } - NavigationTarget::from_module(db, module) - } - - pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { - let src = field.source(db); - match src.ast { - FieldSource::Named(it) => NavigationTarget::from_named( - db, - src.file_id, - &it, - it.doc_comment_text(), - it.short_label(), - ), - FieldSource::Pos(it) => { - let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); - NavigationTarget::from_syntax( - file_id, - "".into(), - None, - text_range, - it.syntax(), - None, - None, - ) - } - } - } - - pub(crate) fn from_def_source(db: &RootDatabase, def: D) -> NavigationTarget - where - D: HasSource, - A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, - { - let src = def.source(db); - NavigationTarget::from_named( - db, - src.file_id, - &src.ast, - src.ast.doc_comment_text(), - src.ast.short_label(), - ) - } - - pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::Adt) -> NavigationTarget { - match adt_def { - hir::Adt::Struct(it) => NavigationTarget::from_def_source(db, it), - hir::Adt::Union(it) => NavigationTarget::from_def_source(db, it), - hir::Adt::Enum(it) => NavigationTarget::from_def_source(db, it), - } + module.to_nav(db) } pub(crate) fn from_def( @@ -239,14 +134,14 @@ impl NavigationTarget { module_def: hir::ModuleDef, ) -> Option { let nav = match module_def { - hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), - hir::ModuleDef::Function(func) => NavigationTarget::from_def_source(db, func), - hir::ModuleDef::Adt(it) => NavigationTarget::from_adt_def(db, it), - hir::ModuleDef::Const(it) => NavigationTarget::from_def_source(db, it), - hir::ModuleDef::Static(it) => NavigationTarget::from_def_source(db, it), - hir::ModuleDef::EnumVariant(it) => NavigationTarget::from_def_source(db, it), - hir::ModuleDef::Trait(it) => NavigationTarget::from_def_source(db, it), - hir::ModuleDef::TypeAlias(it) => NavigationTarget::from_def_source(db, it), + hir::ModuleDef::Module(module) => module.to_nav(db), + hir::ModuleDef::Function(it) => it.to_nav(db), + hir::ModuleDef::Adt(it) => it.to_nav(db), + hir::ModuleDef::Const(it) => it.to_nav(db), + hir::ModuleDef::Static(it) => it.to_nav(db), + hir::ModuleDef::EnumVariant(it) => it.to_nav(db), + hir::ModuleDef::Trait(it) => it.to_nav(db), + hir::ModuleDef::TypeAlias(it) => it.to_nav(db), hir::ModuleDef::BuiltinType(..) => { return None; } @@ -254,41 +149,6 @@ impl NavigationTarget { Some(nav) } - pub(crate) fn from_impl_block( - db: &RootDatabase, - impl_block: hir::ImplBlock, - ) -> NavigationTarget { - let src = impl_block.source(db); - let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); - - NavigationTarget::from_syntax( - file_id, - "impl".into(), - None, - text_range, - src.ast.syntax(), - None, - None, - ) - } - - pub(crate) fn from_assoc_item( - db: &RootDatabase, - assoc_item: hir::AssocItem, - ) -> NavigationTarget { - match assoc_item { - AssocItem::Function(it) => NavigationTarget::from_def_source(db, it), - AssocItem::Const(it) => NavigationTarget::from_def_source(db, it), - AssocItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it), - } - } - - pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { - let src = macro_call.source(db); - log::debug!("nav target {:#?}", src.ast.syntax()); - NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) - } - #[cfg(test)] pub(crate) fn assert_match(&self, expected: &str) { let actual = self.debug_render(); @@ -359,6 +219,172 @@ impl NavigationTarget { } } +impl ToNav for FileSymbol { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + NavigationTarget { + file_id: self.file_id, + name: self.name.clone(), + kind: self.ptr.kind(), + full_range: self.ptr.range(), + focus_range: self.name_range, + container_name: self.container_name.clone(), + description: description_from_symbol(db, self), + docs: docs_from_symbol(db, self), + } + } +} + +pub(crate) trait ToNavFromAst {} +impl ToNavFromAst for hir::Function {} +impl ToNavFromAst for hir::Const {} +impl ToNavFromAst for hir::Static {} +impl ToNavFromAst for hir::Struct {} +impl ToNavFromAst for hir::Enum {} +impl ToNavFromAst for hir::EnumVariant {} +impl ToNavFromAst for hir::Union {} +impl ToNavFromAst for hir::TypeAlias {} +impl ToNavFromAst for hir::Trait {} + +impl ToNav for D +where + D: HasSource + ToNavFromAst + Copy, + D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, +{ + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.source(db); + NavigationTarget::from_named( + db, + src.file_id, + &src.ast, + src.ast.doc_comment_text(), + src.ast.short_label(), + ) + } +} + +impl ToNav for hir::Module { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.definition_source(db); + let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); + match src.ast { + ModuleSource::SourceFile(node) => { + let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); + + NavigationTarget::from_syntax( + file_id, + name, + None, + text_range, + node.syntax(), + None, + None, + ) + } + ModuleSource::Module(node) => { + let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); + + NavigationTarget::from_syntax( + file_id, + name, + None, + text_range, + node.syntax(), + node.doc_comment_text(), + node.short_label(), + ) + } + } + } +} + +impl ToNav for hir::ImplBlock { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.source(db); + let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); + + NavigationTarget::from_syntax( + file_id, + "impl".into(), + None, + text_range, + src.ast.syntax(), + None, + None, + ) + } +} + +impl ToNav for hir::StructField { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.source(db); + + match src.ast { + FieldSource::Named(it) => NavigationTarget::from_named( + db, + src.file_id, + &it, + it.doc_comment_text(), + it.short_label(), + ), + FieldSource::Pos(it) => { + let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); + NavigationTarget::from_syntax( + file_id, + "".into(), + None, + text_range, + it.syntax(), + None, + None, + ) + } + } + } +} + +impl ToNav for hir::MacroDef { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.source(db); + log::debug!("nav target {:#?}", src.ast.syntax()); + NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) + } +} + +impl ToNav for hir::Adt { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + match self { + hir::Adt::Struct(it) => it.to_nav(db), + hir::Adt::Union(it) => it.to_nav(db), + hir::Adt::Enum(it) => it.to_nav(db), + } + } +} + +impl ToNav for hir::AssocItem { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + match self { + AssocItem::Function(it) => it.to_nav(db), + AssocItem::Const(it) => it.to_nav(db), + AssocItem::TypeAlias(it) => it.to_nav(db), + } + } +} + +fn find_range_from_node( + db: &RootDatabase, + src: hir::HirFileId, + node: &SyntaxNode, +) -> (FileId, TextRange) { + let text_range = node.text_range(); + let (file_id, text_range) = src + .expansion_info(db) + .and_then(|expansion_info| expansion_info.find_range(text_range)) + .unwrap_or((src, text_range)); + + // FIXME: handle recursive macro generated macro + (file_id.original_file(db), text_range) +} + pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option { let parse = db.parse(symbol.file_id); let node = symbol.ptr.to_node(parse.tree().syntax()); diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index afa59cbe3..713b61d5e 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -9,7 +9,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - display::ShortLabel, + display::{ShortLabel, ToNav}, references::{classify_name_ref, NameKind::*}, FilePosition, NavigationTarget, RangeInfo, }; @@ -56,16 +56,16 @@ pub(crate) fn reference_definition( let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); match name_kind { - Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), - Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), - Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), + Some(Macro(mac)) => return Exact(mac.to_nav(db)), + Some(Field(field)) => return Exact(field.to_nav(db)), + Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), Some(Def(def)) => match NavigationTarget::from_def(db, def) { Some(nav) => return Exact(nav), None => return Approximate(vec![]), }, Some(SelfType(ty)) => { - if let Some((def_id, _)) = ty.as_adt() { - return Exact(NavigationTarget::from_adt_def(db, def_id)); + if let Some((adt, _)) = ty.as_adt() { + return Exact(adt.to_nav(db)); } } Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), @@ -79,7 +79,7 @@ pub(crate) fn reference_definition( // Fallback index based approach: let navs = crate::symbol_index::index_resolve(db, name_ref) .into_iter() - .map(|s| NavigationTarget::from_symbol(db, s)) + .map(|s| s.to_nav(db)) .collect(); Approximate(navs) } @@ -95,7 +95,7 @@ pub(crate) fn name_definition( if module.has_semi() { let src = hir::Source { file_id: file_id.into(), ast: module }; if let Some(child_module) = hir::Module::from_declaration(db, src) { - let nav = NavigationTarget::from_module(db, child_module); + let nav = child_module.to_nav(db); return Some(vec![nav]); } } diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 059d80524..71146591d 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs @@ -3,7 +3,7 @@ use ra_db::SourceDatabase; use ra_syntax::{ast, AstNode}; -use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; +use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo}; pub(crate) fn goto_type_definition( db: &RootDatabase, @@ -33,7 +33,7 @@ pub(crate) fn goto_type_definition( let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; - let nav = NavigationTarget::from_adt_def(db, adt_def); + let nav = adt_def.to_nav(db); Some(RangeInfo::new(node.text_range(), vec![nav])) } diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index b899ed3a5..bc9b66550 100644 --- a/crates/ra_ide_api/src/impls.rs +++ b/crates/ra_ide_api/src/impls.rs @@ -4,7 +4,7 @@ use hir::{db::HirDatabase, ApplicationTy, FromSource, Ty, TypeCtor}; use ra_db::SourceDatabase; use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; -use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; +use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo}; pub(crate) fn goto_implementation( db: &RootDatabase, @@ -58,7 +58,7 @@ fn impls_for_def( impls .all_impls() .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db))) - .map(|imp| NavigationTarget::from_impl_block(db, imp)) + .map(|imp| imp.to_nav(db)) .collect(), ) } @@ -75,12 +75,7 @@ fn impls_for_trait( let krate = module.krate(); let impls = db.impls_in_crate(krate); - Some( - impls - .lookup_impl_blocks_for_trait(tr) - .map(|imp| NavigationTarget::from_impl_block(db, imp)) - .collect(), - ) + Some(impls.lookup_impl_blocks_for_trait(tr).map(|imp| imp.to_nav(db)).collect()) } fn is_equal_for_find_impls(original_ty: &Ty, impl_ty: &Ty) -> bool { diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index d0188da44..484fbcc82 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -56,7 +56,7 @@ use ra_db::{ }; use ra_syntax::{SourceFile, TextRange, TextUnit}; -use crate::{db::LineIndexDatabase, symbol_index::FileSymbol}; +use crate::{db::LineIndexDatabase, display::ToNav, symbol_index::FileSymbol}; pub use crate::{ assists::{Assist, AssistId}, @@ -351,7 +351,7 @@ impl Analysis { self.with_db(|db| { symbol_index::world_symbols(db, query) .into_iter() - .map(|s| NavigationTarget::from_symbol(db, s)) + .map(|s| s.to_nav(db)) .collect::>() }) } diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index b5b1c9a16..0a76bf484 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -19,7 +19,9 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_prof::profile; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; -use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo}; +use crate::{ + db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, +}; pub(crate) use self::{ classify::{classify_name, classify_name_ref}, @@ -76,12 +78,12 @@ pub(crate) fn find_all_refs( let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; let declaration = match def.kind { - NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), - NameKind::Field(field) => NavigationTarget::from_field(db, field), - NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), + NameKind::Macro(mac) => mac.to_nav(db), + NameKind::Field(field) => field.to_nav(db), + NameKind::AssocItem(assoc) => assoc.to_nav(db), NameKind::Def(def) => NavigationTarget::from_def(db, def)?, NameKind::SelfType(ref ty) => match ty.as_adt() { - Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), + Some((adt, _)) => adt.to_nav(db), None => return None, }, NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), -- cgit v1.2.3 From ef70925f5f4f89f56f113c11bca44fd1a7764d50 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 11 Nov 2019 12:52:14 +0300 Subject: Refactor highlighting to use classify_name --- crates/ra_ide_api/src/syntax_highlighting.rs | 145 ++++++++++++++------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 33f3caceb..1ee68abe2 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -9,12 +9,15 @@ use ra_syntax::{ ast::{self, NameOwner}, AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind, SyntaxKind::*, - TextRange, T, + SyntaxNode, TextRange, T, }; use crate::{ db::RootDatabase, - references::{classify_name_ref, NameKind::*}, + references::{ + classify_name, classify_name_ref, + NameKind::{self, *}, + }, FileId, }; @@ -100,81 +103,43 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", - Some(Field(_)) => "field", - Some(AssocItem(hir::AssocItem::Function(_))) => "function", - Some(AssocItem(hir::AssocItem::Const(_))) => "constant", - Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type", - Some(Def(hir::ModuleDef::Module(_))) => "module", - Some(Def(hir::ModuleDef::Function(_))) => "function", - Some(Def(hir::ModuleDef::Adt(_))) => "type", - Some(Def(hir::ModuleDef::EnumVariant(_))) => "constant", - Some(Def(hir::ModuleDef::Const(_))) => "constant", - Some(Def(hir::ModuleDef::Static(_))) => "constant", - Some(Def(hir::ModuleDef::Trait(_))) => "type", - Some(Def(hir::ModuleDef::TypeAlias(_))) => "type", - Some(Def(hir::ModuleDef::BuiltinType(_))) => "type", - Some(SelfType(_)) => "type", - Some(Pat((_, ptr))) => { - let pat = ptr.to_node(&root); - if let Some(name) = pat.name() { - let text = name.text(); - let shadow_count = - bindings_shadow_count.entry(text.clone()).or_default(); - binding_hash = - Some(calc_binding_hash(file_id, &text, *shadow_count)) - } - let analyzer = - hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); - if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { - "variable.mut" - } else { - "variable" - } - } - Some(SelfParam(_)) => "type", - Some(GenericParam(_)) => "type", - None => "text", + let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); + let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); + + if let Some(Pat((_, ptr))) = &name_kind { + let pat = ptr.to_node(&root); + if let Some(name) = pat.name() { + let text = name.text(); + let shadow_count = bindings_shadow_count.entry(text.clone()).or_default(); + binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) } - } else { - "text" - } + }; + + name_kind + .map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it)) } NAME => { - if let Some(name) = node.as_node().cloned().and_then(ast::Name::cast) { - let analyzer = hir::SourceAnalyzer::new(db, file_id, name.syntax(), None); - if let Some(pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { - if let Some(name) = pat.name() { - let text = name.text(); - let shadow_count = - bindings_shadow_count.entry(text.clone()).or_default(); - *shadow_count += 1; - binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) - } - - if is_variable_mutable(db, &analyzer, pat) { - "variable.mut" - } else { - "variable" - } - } else { - name.syntax() - .parent() - .map(|x| match x.kind() { - TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => { - "type" - } - RECORD_FIELD_DEF => "field", - _ => "function", - }) - .unwrap_or("function") + let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); + let name_kind = classify_name(db, file_id, &name).map(|d| d.kind); + + if let Some(Pat((_, ptr))) = &name_kind { + let pat = ptr.to_node(&root); + if let Some(name) = pat.name() { + let text = name.text(); + let shadow_count = bindings_shadow_count.entry(text.clone()).or_default(); + *shadow_count += 1; + binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) } - } else { - "text" + }; + + match name_kind { + Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind), + None => name.syntax().parent().map_or("function", |x| match x.kind() { + TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", + RECORD_FIELD_DEF => "field", + _ => "function", + }), } } INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", @@ -272,6 +237,42 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo buf } +fn highlight_name( + db: &RootDatabase, + file_id: FileId, + node: &SyntaxNode, + root: &SyntaxNode, + name_kind: NameKind, +) -> &'static str { + match name_kind { + Macro(_) => "macro", + Field(_) => "field", + AssocItem(hir::AssocItem::Function(_)) => "function", + AssocItem(hir::AssocItem::Const(_)) => "constant", + AssocItem(hir::AssocItem::TypeAlias(_)) => "type", + Def(hir::ModuleDef::Module(_)) => "module", + Def(hir::ModuleDef::Function(_)) => "function", + Def(hir::ModuleDef::Adt(_)) => "type", + Def(hir::ModuleDef::EnumVariant(_)) => "constant", + Def(hir::ModuleDef::Const(_)) => "constant", + Def(hir::ModuleDef::Static(_)) => "constant", + Def(hir::ModuleDef::Trait(_)) => "type", + Def(hir::ModuleDef::TypeAlias(_)) => "type", + Def(hir::ModuleDef::BuiltinType(_)) => "type", + SelfType(_) => "type", + SelfParam(_) => "type", + GenericParam(_) => "type", + Pat((_, ptr)) => { + let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None); + if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { + "variable.mut" + } else { + "variable" + } + } + } +} + //FIXME: like, real html escaping fn html_escape(text: &str) -> String { text.replace("<", "<").replace(">", ">") -- cgit v1.2.3 From 4f7df2aac107c0de2cab851f2a4f1ab369511fc8 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 11 Nov 2019 18:45:55 +0800 Subject: Add MacroDefKind --- crates/ra_hir/src/code_model/src.rs | 11 +++-------- crates/ra_hir_def/src/nameres/collector.rs | 15 +++++++-------- crates/ra_hir_expand/src/builtin_macro.rs | 8 ++------ crates/ra_hir_expand/src/db.rs | 12 ++++++------ crates/ra_hir_expand/src/hygiene.rs | 8 ++++---- crates/ra_hir_expand/src/lib.rs | 26 +++++++------------------- 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index c4e62f799..6d116ee75 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -6,8 +6,8 @@ use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, ids::AstItemDef, - Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, - MacroDefId, Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, + Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module, + ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; pub use hir_expand::Source; @@ -140,15 +140,10 @@ impl HasSource for TypeAlias { self.id.source(db) } } - impl HasSource for MacroDef { type Ast = ast::MacroCall; fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - let ast_id = match self.id { - MacroDefId::DeclarativeMacro(it) => it.ast_id, - MacroDefId::BuiltinMacro(it) => it.ast_id, - }; - Source { file_id: ast_id.file_id(), ast: ast_id.to_node(db) } + Source { file_id: self.id.ast_id.file_id(), ast: self.id.ast_id.to_node(db) } } } diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 5f18e9de3..30664278e 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -3,7 +3,7 @@ use hir_expand::{ builtin_macro::find_builtin_macro, name::{self, AsName, Name}, - DeclarativeMacro, HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind, + HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFileKind, }; use ra_cfg::CfgOptions; use ra_db::{CrateId, FileId}; @@ -708,13 +708,12 @@ 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 = DeclarativeMacro { ast_id, krate: self.def_collector.def_map.krate }; - self.def_collector.define_macro( - self.module_id, - name.clone(), - MacroDefId::DeclarativeMacro(macro_id), - mac.export, - ); + let macro_id = MacroDefId { + ast_id, + krate: self.def_collector.def_map.krate, + kind: MacroDefKind::Declarative, + }; + self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); } return; } diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index acb62da27..97fb0cb55 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -2,7 +2,7 @@ use crate::db::AstDatabase; use crate::{ ast::{self, AstNode}, - name, AstId, BuiltinMacro, CrateId, HirFileId, MacroCallId, MacroDefId, MacroFileKind, + name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, TextUnit, }; @@ -33,11 +33,7 @@ pub fn find_builtin_macro( ) -> Option { // FIXME: Better registering method if ident == &name::LINE_MACRO { - Some(MacroDefId::BuiltinMacro(BuiltinMacro { - expander: BuiltinExpander::Line, - krate, - ast_id, - })) + Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) }) } else { None } diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 009ff5312..5eadee9c2 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs @@ -10,7 +10,7 @@ use ra_syntax::{AstNode, Parse, SyntaxNode}; use crate::{ ast_id_map::AstIdMap, BuiltinExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, - MacroDefId, MacroFile, MacroFileKind, + MacroDefId, MacroDefKind, MacroFile, MacroFileKind, }; #[derive(Debug, Clone, Eq, PartialEq)] @@ -69,9 +69,9 @@ pub(crate) fn macro_def( db: &dyn AstDatabase, id: MacroDefId, ) -> Option> { - match id { - MacroDefId::DeclarativeMacro(it) => { - let macro_call = it.ast_id.to_node(db); + match id.kind { + MacroDefKind::Declarative => { + let macro_call = id.ast_id.to_node(db); let arg = macro_call.token_tree()?; let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { log::warn!("fail on macro_def to token tree: {:#?}", arg); @@ -83,8 +83,8 @@ pub(crate) fn macro_def( })?; Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) } - MacroDefId::BuiltinMacro(it) => { - Some(Arc::new((TokenExpander::Builtin(it.expander.clone()), mbe::TokenMap::default()))) + MacroDefKind::BuiltIn(expander) => { + Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) } } } diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 6b682d3ab..379562a2c 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -9,7 +9,7 @@ use crate::{ db::AstDatabase, either::Either, name::{AsName, Name}, - HirFileId, HirFileIdRepr, MacroDefId, + HirFileId, HirFileIdRepr, MacroDefKind, }; #[derive(Debug)] @@ -24,9 +24,9 @@ impl Hygiene { HirFileIdRepr::FileId(_) => None, HirFileIdRepr::MacroFile(macro_file) => { let loc = db.lookup_intern_macro(macro_file.macro_call_id); - match loc.def { - MacroDefId::DeclarativeMacro(it) => Some(it.krate), - MacroDefId::BuiltinMacro(_) => None, + match loc.def.kind { + MacroDefKind::Declarative => Some(loc.def.krate), + MacroDefKind::BuiltIn(_) => None, } } }; diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 21d666f13..c6ffa2c6f 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -78,15 +78,9 @@ impl HirFileId { HirFileIdRepr::MacroFile(macro_file) => { let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); - // FIXME: Do we support expansion information in builtin macro? - let macro_decl = match loc.def { - MacroDefId::DeclarativeMacro(it) => (it), - MacroDefId::BuiltinMacro(_) => return None, - }; - let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); let def_start = - macro_decl.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); + loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start(); let macro_def = db.macro_def(loc.def)?; let shift = macro_def.0.shift(); @@ -94,7 +88,7 @@ impl HirFileId { let macro_arg = db.macro_arg(macro_file.macro_call_id)?; let arg_start = (loc.ast_id.file_id, arg_start); - let def_start = (macro_decl.ast_id.file_id, def_start); + let def_start = (loc.def.ast_id.file_id, def_start); Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift }) } @@ -128,22 +122,16 @@ impl salsa::InternKey for MacroCallId { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum MacroDefId { - DeclarativeMacro(DeclarativeMacro), - BuiltinMacro(BuiltinMacro), -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DeclarativeMacro { +pub struct MacroDefId { pub krate: CrateId, pub ast_id: AstId, + pub kind: MacroDefKind, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct BuiltinMacro { - pub krate: CrateId, - pub ast_id: AstId, - pub expander: BuiltinExpander, +pub enum MacroDefKind { + Declarative, + BuiltIn(BuiltinExpander), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -- cgit v1.2.3 From 8b7f853cc19d0940ec542e10bc23aa78455bbb3b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 10 Nov 2019 00:32:00 +0300 Subject: Add hir::Local --- crates/ra_hir/src/code_model.rs | 55 ++++++++++++++- crates/ra_hir/src/expr/scope.rs | 2 +- crates/ra_hir/src/from_source.rs | 30 +++++++- crates/ra_hir/src/lib.rs | 2 +- crates/ra_hir/src/source_binder.rs | 20 +++--- crates/ra_ide_api/src/display/navigation_target.rs | 70 ++++++++----------- crates/ra_ide_api/src/goto_definition.rs | 3 +- crates/ra_ide_api/src/hover.rs | 2 +- crates/ra_ide_api/src/references.rs | 3 +- crates/ra_ide_api/src/references/classify.rs | 22 +++--- .../ra_ide_api/src/references/name_definition.rs | 38 +---------- crates/ra_ide_api/src/references/search_scope.rs | 6 +- .../src/snapshots/rainbow_highlighting.html | 12 ++-- crates/ra_ide_api/src/syntax_highlighting.rs | 79 ++++++---------------- 14 files changed, 171 insertions(+), 173 deletions(-) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e5bfad3ca..09c4e97fa 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, - expr::{validation::ExprValidator, Body, BodySourceMap}, + expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, generics::HasGenericParams, ids::{ AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, @@ -32,7 +32,7 @@ use crate::{ resolve::{Resolver, Scope, TypeNs}, traits::TraitData, ty::{InferenceResult, Namespace, TraitRef}, - Either, HasSource, ImportId, Name, ScopeDef, Ty, + Either, HasSource, ImportId, Name, ScopeDef, Source, Ty, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -1070,3 +1070,54 @@ impl AssocItem { .expect("AssocItem without container") } } + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Local { + pub(crate) parent: DefWithBody, + pub(crate) pat_id: PatId, +} + +impl Local { + pub fn name(self, db: &impl HirDatabase) -> Option { + let body = db.body_hir(self.parent); + match &body[self.pat_id] { + Pat::Bind { name, .. } => Some(name.clone()), + _ => None, + } + } + + pub fn is_self(self, db: &impl HirDatabase) -> bool { + self.name(db) == Some(name::SELF_PARAM) + } + + pub fn is_mut(self, db: &impl HirDatabase) -> bool { + let body = db.body_hir(self.parent); + match &body[self.pat_id] { + Pat::Bind { mode, .. } => match mode { + BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, + _ => false, + }, + _ => false, + } + } + + pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody { + self.parent + } + + pub fn module(self, db: &impl HirDatabase) -> Module { + self.parent.module(db) + } + + pub fn ty(self, db: &impl HirDatabase) -> Ty { + let infer = db.infer(self.parent); + infer[self.pat_id].clone() + } + + pub fn source(self, db: &impl HirDatabase) -> Source> { + let (_body, source_map) = db.body_with_source_map(self.parent); + let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... + let root = src.file_syntax(db); + src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) + } +} diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 5a1eade2c..daf8d8d07 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs @@ -17,7 +17,7 @@ impl_arena_id!(ScopeId); #[derive(Debug, PartialEq, Eq)] pub struct ExprScopes { - body: Arc, + pub(crate) body: Arc, scopes: Arena, scope_by_expr: FxHashMap, } diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index c95d2cdd0..2c441b0f4 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -2,13 +2,17 @@ use hir_def::{StructId, StructOrUnionId, UnionId}; use hir_expand::name::AsName; -use ra_syntax::ast::{self, AstNode, NameOwner}; +use ra_syntax::{ + ast::{self, AstNode, NameOwner}, + match_ast, +}; use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, - AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, - ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, + AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, + ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, + Union, VariantDef, }; pub trait FromSource: Sized { @@ -126,6 +130,26 @@ impl FromSource for StructField { } } +impl Local { + pub fn from_source(db: &impl HirDatabase, src: Source) -> Option { + let file_id = src.file_id; + let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| { + let res = match_ast! { + match it { + ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() }, + ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() }, + ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() }, + _ => return None, + } + }; + Some(res) + })?; + let (_body, source_map) = db.body_with_source_map(parent); + let pat_id = source_map.node_pat(&src.ast.into())?; + Some(Local { parent, pat_id }) + } +} + 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 9dc8d139b..806f1daed 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -65,7 +65,7 @@ pub use crate::{ docs::{DocDef, Docs, Documentation}, src::{HasBodySource, HasSource}, Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, - EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, + EnumVariant, FieldSource, FnData, Function, HasBody, Local, MacroDef, Module, ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }, expr::ExprScopes, diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 66cb4b357..c5fdf3bab 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -28,7 +28,7 @@ use crate::{ ids::LocationCtx, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::{self, implements_trait}, - AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, + AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, }; @@ -94,6 +94,7 @@ fn def_with_body_from_child_node( #[derive(Debug)] pub struct SourceAnalyzer { resolver: Resolver, + body_owner: Option, body_source_map: Option>, infer: Option>, scopes: Option>, @@ -104,7 +105,7 @@ pub enum PathResolution { /// An item Def(crate::ModuleDef), /// A local binding (only value namespace) - LocalBinding(Either, AstPtr>), + Local(Local), /// A generic parameter GenericParam(u32), SelfType(crate::ImplBlock), @@ -152,6 +153,7 @@ impl SourceAnalyzer { let resolver = expr::resolver_for_scope(def.body(db), db, scope); SourceAnalyzer { resolver, + body_owner: Some(def), body_source_map: Some(source_map), infer: Some(def.infer(db)), scopes: Some(scopes), @@ -162,6 +164,7 @@ impl SourceAnalyzer { .ancestors() .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) .unwrap_or_default(), + body_owner: None, body_source_map: None, infer: None, scopes: None, @@ -233,16 +236,9 @@ impl SourceAnalyzer { }); let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { let res = match val { - ValueNs::LocalBinding(it) => { - // We get a `PatId` from resolver, but it actually can only - // point at `BindPat`, and not at the arbitrary pattern. - let pat_ptr = self - .body_source_map - .as_ref()? - .pat_syntax(it)? - .ast // FIXME: ignoring file_id here is definitelly wrong - .map_a(|ptr| ptr.cast::().unwrap()); - PathResolution::LocalBinding(pat_ptr) + ValueNs::LocalBinding(pat_id) => { + let var = Local { parent: self.body_owner?, pat_id }; + PathResolution::Local(var) } ValueNs::Function(it) => PathResolution::Def(it.into()), ValueNs::Const(it) => PathResolution::Def(it.into()), diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 41d467564..f7ad08515 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs @@ -1,11 +1,11 @@ //! FIXME: write short doc here -use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; +use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource}; use ra_db::{FileId, SourceDatabase}; use ra_syntax::{ - ast::{self, DocCommentsOwner}, - match_ast, AstNode, AstPtr, SmolStr, - SyntaxKind::{self, NAME}, + ast::{self, DocCommentsOwner, NameOwner}, + match_ast, AstNode, SmolStr, + SyntaxKind::{self, BIND_PAT}, SyntaxNode, TextRange, }; @@ -76,42 +76,6 @@ impl NavigationTarget { self.focus_range } - pub(crate) fn from_bind_pat( - db: &RootDatabase, - file_id: FileId, - pat: &ast::BindPat, - ) -> NavigationTarget { - NavigationTarget::from_named(db, file_id.into(), pat, None, None) - } - - pub(crate) fn from_pat( - db: &RootDatabase, - file_id: FileId, - pat: AstPtr, - ) -> NavigationTarget { - let parse = db.parse(file_id); - let pat = pat.to_node(parse.tree().syntax()); - NavigationTarget::from_bind_pat(db, file_id, &pat) - } - - pub(crate) fn from_self_param( - file_id: FileId, - par: AstPtr, - ) -> NavigationTarget { - let (name, full_range) = ("self".into(), par.syntax_node_ptr().range()); - - NavigationTarget { - file_id, - name, - full_range, - focus_range: None, - kind: NAME, - container_name: None, - description: None, //< No document node for SelfParam - docs: None, //< No document node for SelfParam - } - } - pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); if let Some(src) = module.declaration_source(db) { @@ -370,6 +334,32 @@ impl ToNav for hir::AssocItem { } } +impl ToNav for hir::Local { + fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { + let src = self.source(db); + let (full_range, focus_range) = match src.ast { + Either::A(it) => { + (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) + } + Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), + }; + let name = match self.name(db) { + Some(it) => it.to_string().into(), + None => "".into(), + }; + NavigationTarget { + file_id: src.file_id.original_file(db), + name, + kind: BIND_PAT, + full_range, + focus_range, + container_name: None, + description: None, + docs: None, + } + } +} + fn find_range_from_node( db: &RootDatabase, src: hir::HirFileId, diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 713b61d5e..6c8387f6c 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -68,8 +68,7 @@ pub(crate) fn reference_definition( return Exact(adt.to_nav(db)); } } - Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), - Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)), + Some(Local(local)) => return Exact(local.to_nav(db)), Some(GenericParam(_)) => { // FIXME: go to the generic param def } diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index cc41390b2..086e6dec3 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -143,7 +143,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option { + Some(Local(_)) => { // Hover for these shows type names no_fallback = true; } diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 0a76bf484..9cb9433e7 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -86,8 +86,7 @@ pub(crate) fn find_all_refs( Some((adt, _)) => adt.to_nav(db), None => return None, }, - NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), - NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), + NameKind::Local(local) => local.to_nav(db), NameKind::GenericParam(_) => return None, }; diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 153082d5b..217f9951e 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -1,13 +1,13 @@ //! Functions that are used to classify an element from its definition or reference. -use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; +use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; use ra_db::FileId; use ra_prof::profile; -use ra_syntax::{ast, match_ast, AstNode, AstPtr}; +use ra_syntax::{ast, match_ast, AstNode}; use test_utils::tested_by; use super::{ - name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, + name_definition::{from_assoc_item, from_module_def, from_struct_field}, NameDefinition, NameKind, }; use crate::db::RootDatabase; @@ -25,7 +25,13 @@ pub(crate) fn classify_name( match_ast! { match parent { ast::BindPat(it) => { - from_pat(db, file_id, AstPtr::new(&it)) + let src = hir::Source { file_id, ast: it }; + let local = hir::Local::from_source(db, src)?; + Some(NameDefinition { + visibility: None, + container: local.module(db), + kind: NameKind::Local(local), + }) }, ast::RecordFieldDef(it) => { let ast = hir::FieldSource::Named(it); @@ -159,10 +165,10 @@ pub(crate) fn classify_name_ref( match resolved { Def(def) => Some(from_module_def(db, def, Some(container))), AssocItem(item) => Some(from_assoc_item(db, item)), - LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), - LocalBinding(Either::B(par)) => { - let kind = NameKind::SelfParam(par); - Some(NameDefinition { kind, container, visibility }) + Local(local) => { + let container = local.module(db); + let kind = NameKind::Local(local); + Some(NameDefinition { kind, container, visibility: None }) } GenericParam(par) => { // FIXME: get generic param def diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs index 4580bc789..450f7ea9b 100644 --- a/crates/ra_ide_api/src/references/name_definition.rs +++ b/crates/ra_ide_api/src/references/name_definition.rs @@ -4,10 +4,9 @@ //! Note that the reference search is possible for not all of the classified items. use hir::{ - db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, - Module, ModuleDef, StructField, Ty, VariantDef, + Adt, AssocItem, HasSource, Local, MacroDef, Module, ModuleDef, StructField, Ty, VariantDef, }; -use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; +use ra_syntax::{ast, ast::VisibilityOwner}; use crate::db::RootDatabase; @@ -18,8 +17,7 @@ pub enum NameKind { AssocItem(AssocItem), Def(ModuleDef), SelfType(Ty), - Pat((DefWithBody, AstPtr)), - SelfParam(AstPtr), + Local(Local), GenericParam(u32), } @@ -30,36 +28,6 @@ pub(crate) struct NameDefinition { pub kind: NameKind, } -pub(super) fn from_pat( - db: &RootDatabase, - file_id: HirFileId, - pat: AstPtr, -) -> Option { - let root = db.parse_or_expand(file_id)?; - let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { - match_ast! { - match node { - ast::FnDef(it) => { - let src = hir::Source { file_id, ast: it }; - Some(hir::Function::from_source(db, src)?.into()) - }, - ast::ConstDef(it) => { - let src = hir::Source { file_id, ast: it }; - Some(hir::Const::from_source(db, src)?.into()) - }, - ast::StaticDef(it) => { - let src = hir::Source { file_id, ast: it }; - Some(hir::Static::from_source(db, src)?.into()) - }, - _ => None, - } - } - })?; - let kind = NameKind::Pat((def, pat)); - let container = def.module(db); - Some(NameDefinition { kind, container, visibility: None }) -} - pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { let container = item.module(db); let visibility = match item { diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index f2789e0b2..2907787c2 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -71,13 +71,13 @@ impl NameDefinition { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); - if let NameKind::Pat((def, _)) = self.kind { - let mut res = FxHashMap::default(); - let range = match def { + if let NameKind::Local(var) = self.kind { + let range = match var.parent(db) { DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; + let mut res = FxHashMap::default(); res.insert(file_id, Some(range)); return SearchScope::new(res); } diff --git a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html index ed664817e..79f11ea80 100644 --- a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html @@ -20,14 +20,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .keyword\.control { color: #F0DFAF; font-weight: bold; }
fn main() {
-    let hello = "hello";
-    let x = hello.to_string();
-    let y = hello.to_string();
+    let hello = "hello";
+    let x = hello.to_string();
+    let y = hello.to_string();
 
-    let x = "other color please!";
-    let y = x.to_string();
+    let x = "other color please!";
+    let y = x.to_string();
 }
 
 fn bar() {
-    let mut hello = "hello";
+    let mut hello = "hello";
 }
\ No newline at end of file diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 1ee68abe2..d53a759ee 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -2,15 +2,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; -use hir::{Mutability, Ty}; +use hir::{Mutability, Name}; use ra_db::SourceDatabase; use ra_prof::profile; -use ra_syntax::{ - ast::{self, NameOwner}, - AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind, - SyntaxKind::*, - SyntaxNode, TextRange, T, -}; +use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; use crate::{ db::RootDatabase, @@ -43,32 +38,12 @@ fn is_control_keyword(kind: SyntaxKind) -> bool { } } -fn is_variable_mutable( - db: &RootDatabase, - analyzer: &hir::SourceAnalyzer, - pat: ast::BindPat, -) -> bool { - if pat.is_mutable() { - return true; - } - - let ty = analyzer.type_of_pat(db, &pat.into()).unwrap_or(Ty::Unknown); - if let Some((_, mutability)) = ty.as_reference() { - match mutability { - Mutability::Shared => false, - Mutability::Mut => true, - } - } else { - false - } -} - pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec { let _p = profile("highlight"); let parse = db.parse(file_id); let root = parse.tree().syntax().clone(); - fn calc_binding_hash(file_id: FileId, text: &SmolStr, shadow_count: u32) -> u64 { + fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 { fn hash(x: T) -> u64 { use std::{collections::hash_map::DefaultHasher, hash::Hasher}; @@ -77,13 +52,13 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec = FxHashSet::default(); - let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); + let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); let mut res = Vec::new(); for node in root.descendants_with_tokens() { @@ -107,34 +82,29 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec { let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); let name_kind = classify_name(db, file_id, &name).map(|d| d.kind); - if let Some(Pat((_, ptr))) = &name_kind { - let pat = ptr.to_node(&root); - if let Some(name) = pat.name() { - let text = name.text(); - let shadow_count = bindings_shadow_count.entry(text.clone()).or_default(); + if let Some(Local(local)) = &name_kind { + if let Some(name) = local.name(db) { + let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); *shadow_count += 1; - binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) + binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count)) } }; match name_kind { - Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind), + Some(name_kind) => highlight_name(db, name_kind), None => name.syntax().parent().map_or("function", |x| match x.kind() { TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", RECORD_FIELD_DEF => "field", @@ -237,13 +207,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo buf } -fn highlight_name( - db: &RootDatabase, - file_id: FileId, - node: &SyntaxNode, - root: &SyntaxNode, - name_kind: NameKind, -) -> &'static str { +fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { match name_kind { Macro(_) => "macro", Field(_) => "field", @@ -260,14 +224,15 @@ fn highlight_name( Def(hir::ModuleDef::TypeAlias(_)) => "type", Def(hir::ModuleDef::BuiltinType(_)) => "type", SelfType(_) => "type", - SelfParam(_) => "type", GenericParam(_) => "type", - Pat((_, ptr)) => { - let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None); - if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { + Local(local) => { + if local.is_mut(db) { "variable.mut" } else { - "variable" + match local.ty(db).as_reference() { + Some((_, Mutability::Mut)) => "variable.mut", + _ => "variable", + } } } } -- cgit v1.2.3