mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Merge pull request #18610 from Veykril/push-kynytqktmnxq
Add implict unsafety inlay hints for extern blocks
This commit is contained in:
commit
632ca53df4
2 changed files with 157 additions and 2 deletions
|
@ -29,6 +29,7 @@ mod closing_brace;
|
||||||
mod closure_captures;
|
mod closure_captures;
|
||||||
mod closure_ret;
|
mod closure_ret;
|
||||||
mod discriminant;
|
mod discriminant;
|
||||||
|
mod extern_block;
|
||||||
mod generic_param;
|
mod generic_param;
|
||||||
mod implicit_drop;
|
mod implicit_drop;
|
||||||
mod implicit_static;
|
mod implicit_static;
|
||||||
|
@ -116,6 +117,7 @@ pub(crate) fn inlay_hints(
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct InlayHintCtx {
|
struct InlayHintCtx {
|
||||||
lifetime_stacks: Vec<Vec<SmolStr>>,
|
lifetime_stacks: Vec<Vec<SmolStr>>,
|
||||||
|
extern_block_parent: Option<ast::ExternBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inlay_hints_resolve(
|
pub(crate) fn inlay_hints_resolve(
|
||||||
|
@ -174,12 +176,18 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<S
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
ctx.lifetime_stacks.push(params);
|
ctx.lifetime_stacks.push(params);
|
||||||
}
|
}
|
||||||
|
if let Some(node) = ast::ExternBlock::cast(node.clone()) {
|
||||||
|
ctx.extern_block_parent = Some(node);
|
||||||
|
}
|
||||||
Some(node)
|
Some(node)
|
||||||
}
|
}
|
||||||
WalkEvent::Leave(n) => {
|
WalkEvent::Leave(n) => {
|
||||||
if ast::AnyHasGenericParams::can_cast(n.kind()) {
|
if ast::AnyHasGenericParams::can_cast(n.kind()) {
|
||||||
ctx.lifetime_stacks.pop();
|
ctx.lifetime_stacks.pop();
|
||||||
}
|
}
|
||||||
|
if ast::ExternBlock::can_cast(n.kind()) {
|
||||||
|
ctx.extern_block_parent = None;
|
||||||
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,12 +242,20 @@ fn hints(
|
||||||
ast::Item(it) => match it {
|
ast::Item(it) => match it {
|
||||||
ast::Item::Fn(it) => {
|
ast::Item::Fn(it) => {
|
||||||
implicit_drop::hints(hints, famous_defs, config, file_id, &it);
|
implicit_drop::hints(hints, famous_defs, config, file_id, &it);
|
||||||
|
if let Some(extern_block) = &ctx.extern_block_parent {
|
||||||
|
extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block);
|
||||||
|
}
|
||||||
lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it)
|
lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it)
|
||||||
},
|
},
|
||||||
// static type elisions
|
ast::Item::Static(it) => {
|
||||||
ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)),
|
if let Some(extern_block) = &ctx.extern_block_parent {
|
||||||
|
extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block);
|
||||||
|
}
|
||||||
|
implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it))
|
||||||
|
},
|
||||||
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
|
ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
|
||||||
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
|
ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
|
||||||
|
ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
// FIXME: trait object type elisions
|
// FIXME: trait object type elisions
|
||||||
|
@ -368,6 +384,7 @@ pub enum InlayKind {
|
||||||
Type,
|
Type,
|
||||||
Drop,
|
Drop,
|
||||||
RangeExclusive,
|
RangeExclusive,
|
||||||
|
ExternUnsafety,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
|
138
crates/ide/src/inlay_hints/extern_block.rs
Normal file
138
crates/ide/src/inlay_hints/extern_block.rs
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
//! Extern block hints
|
||||||
|
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
|
||||||
|
use span::EditionedFileId;
|
||||||
|
use syntax::{ast, AstNode, SyntaxToken};
|
||||||
|
|
||||||
|
use crate::{InlayHint, InlayHintsConfig};
|
||||||
|
|
||||||
|
pub(super) fn extern_block_hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
|
_config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
|
extern_block: ast::ExternBlock,
|
||||||
|
) -> Option<()> {
|
||||||
|
if extern_block.unsafe_token().is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let abi = extern_block.abi()?;
|
||||||
|
acc.push(InlayHint {
|
||||||
|
range: abi.syntax().text_range(),
|
||||||
|
position: crate::InlayHintPosition::Before,
|
||||||
|
pad_left: false,
|
||||||
|
pad_right: true,
|
||||||
|
kind: crate::InlayKind::ExternUnsafety,
|
||||||
|
label: crate::InlayHintLabel::from("unsafe"),
|
||||||
|
text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())),
|
||||||
|
resolve_parent: Some(extern_block.syntax().text_range()),
|
||||||
|
});
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn fn_hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
|
_config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
|
fn_: &ast::Fn,
|
||||||
|
extern_block: &ast::ExternBlock,
|
||||||
|
) -> Option<()> {
|
||||||
|
let implicit_unsafe = fn_.safe_token().is_none() && fn_.unsafe_token().is_none();
|
||||||
|
if !implicit_unsafe {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let fn_ = fn_.fn_token()?;
|
||||||
|
acc.push(item_hint(extern_block, fn_));
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn static_hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
|
_config: &InlayHintsConfig,
|
||||||
|
_file_id: EditionedFileId,
|
||||||
|
static_: &ast::Static,
|
||||||
|
extern_block: &ast::ExternBlock,
|
||||||
|
) -> Option<()> {
|
||||||
|
let implicit_unsafe = static_.safe_token().is_none() && static_.unsafe_token().is_none();
|
||||||
|
if !implicit_unsafe {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let static_ = static_.static_token()?;
|
||||||
|
acc.push(item_hint(extern_block, static_));
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
|
||||||
|
InlayHint {
|
||||||
|
range: token.text_range(),
|
||||||
|
position: crate::InlayHintPosition::Before,
|
||||||
|
pad_left: false,
|
||||||
|
pad_right: true,
|
||||||
|
kind: crate::InlayKind::ExternUnsafety,
|
||||||
|
label: crate::InlayHintLabel::from("unsafe"),
|
||||||
|
text_edit: {
|
||||||
|
let mut builder = TextEdit::builder();
|
||||||
|
builder.insert(token.text_range().start(), "unsafe ".to_owned());
|
||||||
|
if extern_block.unsafe_token().is_none() {
|
||||||
|
if let Some(abi) = extern_block.abi() {
|
||||||
|
builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(builder.finish())
|
||||||
|
},
|
||||||
|
resolve_parent: Some(extern_block.syntax().text_range()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unadorned() {
|
||||||
|
check_with_config(
|
||||||
|
DISABLED_CONFIG,
|
||||||
|
r#"
|
||||||
|
extern "C" {
|
||||||
|
//^^^^^^^^^^ unsafe
|
||||||
|
static FOO: ();
|
||||||
|
// ^^^^^^ unsafe
|
||||||
|
pub static FOO: ();
|
||||||
|
// ^^^^^^unsafe
|
||||||
|
unsafe static FOO: ();
|
||||||
|
safe static FOO: ();
|
||||||
|
fn foo();
|
||||||
|
// ^^ unsafe
|
||||||
|
pub fn foo();
|
||||||
|
// ^^ unsafe
|
||||||
|
unsafe fn foo();
|
||||||
|
safe fn foo();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn adorned() {
|
||||||
|
check_with_config(
|
||||||
|
DISABLED_CONFIG,
|
||||||
|
r#"
|
||||||
|
unsafe extern "C" {
|
||||||
|
static FOO: ();
|
||||||
|
// ^^^^^^ unsafe
|
||||||
|
pub static FOO: ();
|
||||||
|
// ^^^^^^unsafe
|
||||||
|
unsafe static FOO: ();
|
||||||
|
safe static FOO: ();
|
||||||
|
fn foo();
|
||||||
|
// ^^ unsafe
|
||||||
|
pub fn foo();
|
||||||
|
// ^^ unsafe
|
||||||
|
unsafe fn foo();
|
||||||
|
safe fn foo();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue