aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-06-04 16:03:18 +0100
committerLukas Wirth <[email protected]>2021-06-04 16:03:18 +0100
commit5d17b6a6873d530eda89d271807dcb70a811a200 (patch)
tree88b06d926b9311a214d937641990395c5af896de /crates/ide
parentcd46255d7e8bb59b93a32d5cb50581f418ca5f3b (diff)
Implement hover for lints
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/hover.rs90
1 files changed, 84 insertions, 6 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 04598cd06..4d91c5c4f 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -3,6 +3,7 @@ use hir::{
3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module, 3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
4 ModuleDef, Semantics, 4 ModuleDef, Semantics,
5}; 5};
6use ide_completion::generated_lint_completions::{CLIPPY_LINTS, FEATURES};
6use ide_db::{ 7use ide_db::{
7 base_db::SourceDatabase, 8 base_db::SourceDatabase,
8 defs::{Definition, NameClass, NameRefClass}, 9 defs::{Definition, NameClass, NameRefClass},
@@ -11,7 +12,10 @@ use ide_db::{
11}; 12};
12use itertools::Itertools; 13use itertools::Itertools;
13use stdx::format_to; 14use stdx::format_to;
14use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 15use syntax::{
16 algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxKind::*, SyntaxToken, TokenAtOffset,
17 T,
18};
15 19
16use crate::{ 20use crate::{
17 display::{macro_label, TryToNav}, 21 display::{macro_label, TryToNav},
@@ -115,8 +119,8 @@ pub(crate) fn hover(
115 |d| d.defined(db), 119 |d| d.defined(db),
116 ), 120 ),
117 121
118 _ => ast::Comment::cast(token.clone()) 122 _ => {
119 .and_then(|_| { 123 if ast::Comment::cast(token.clone()).is_some() {
120 let (attributes, def) = doc_attributes(&sema, &node)?; 124 let (attributes, def) = doc_attributes(&sema, &node)?;
121 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; 125 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
122 let (idl_range, link, ns) = 126 let (idl_range, link, ns) =
@@ -129,9 +133,11 @@ pub(crate) fn hover(
129 } 133 }
130 })?; 134 })?;
131 range = Some(idl_range); 135 range = Some(idl_range);
132 resolve_doc_path_for_def(db, def, &link, ns) 136 resolve_doc_path_for_def(db, def, &link, ns).map(Definition::ModuleDef)
133 }) 137 } else {
134 .map(Definition::ModuleDef), 138 return try_hover_for_attribute(&token);
139 }
140 },
135 } 141 }
136 }; 142 };
137 143
@@ -194,6 +200,40 @@ pub(crate) fn hover(
194 Some(RangeInfo::new(range, res)) 200 Some(RangeInfo::new(range, res))
195} 201}
196 202
203fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
204 let attr = token.ancestors().nth(1).and_then(ast::Attr::cast)?;
205 let (path, tt) = attr.as_simple_call()?;
206 if !tt.syntax().text_range().contains(token.text_range().start()) {
207 return None;
208 }
209 let lints = match &*path {
210 "feature" => FEATURES,
211 "allow" | "warn" | "forbid" | "error" => {
212 let is_clippy = algo::skip_trivia_token(token.clone(), Direction::Prev)
213 .filter(|t| t.kind() == T![::])
214 .and_then(|t| algo::skip_trivia_token(t, Direction::Prev))
215 .map_or(false, |t| t.kind() == T![ident] && t.text() == "clippy");
216 if is_clippy {
217 CLIPPY_LINTS
218 } else {
219 &[]
220 }
221 }
222 _ => return None,
223 };
224 let lint = lints
225 .binary_search_by_key(&token.text(), |lint| lint.label)
226 .ok()
227 .map(|idx| &FEATURES[idx])?;
228 Some(RangeInfo::new(
229 token.text_range(),
230 HoverResult {
231 markup: Markup::from(format!("```\n{}\n```\n___\n\n{}", lint.label, lint.description)),
232 ..Default::default()
233 },
234 ))
235}
236
197fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 237fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
198 fn to_action(nav_target: NavigationTarget) -> HoverAction { 238 fn to_action(nav_target: NavigationTarget) -> HoverAction {
199 HoverAction::Implementation(FilePosition { 239 HoverAction::Implementation(FilePosition {
@@ -3977,4 +4017,42 @@ pub fn foo() {}
3977 "#]], 4017 "#]],
3978 ) 4018 )
3979 } 4019 }
4020
4021 #[test]
4022 fn hover_feature() {
4023 check(
4024 r#"#![feature(box_syntax$0)]"#,
4025 expect![[r##"
4026 *box_syntax*
4027 ```
4028 box_syntax
4029 ```
4030 ___
4031
4032 # `box_syntax`
4033
4034 The tracking issue for this feature is: [#49733]
4035
4036 [#49733]: https://github.com/rust-lang/rust/issues/49733
4037
4038 See also [`box_patterns`](box-patterns.md)
4039
4040 ------------------------
4041
4042 Currently the only stable way to create a `Box` is via the `Box::new` method.
4043 Also it is not possible in stable Rust to destructure a `Box` in a match
4044 pattern. The unstable `box` keyword can be used to create a `Box`. An example
4045 usage would be:
4046
4047 ```rust
4048 #![feature(box_syntax)]
4049
4050 fn main() {
4051 let b = box 5;
4052 }
4053 ```
4054
4055 "##]],
4056 )
4057 }
3980} 4058}