Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #19274 from Veykril/push-pouwrwwrlrlt
Highlight unsafe operations as unsafe, not definitions
Lukas Wirth 2025-03-05
parent b139e21 · parent 9fc0ffe · commit 27dc614
-rw-r--r--crates/hir-ty/src/diagnostics.rs5
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs42
-rw-r--r--crates/hir/src/semantics.rs113
-rw-r--r--crates/hir/src/source_analyzer.rs4
-rw-r--r--crates/ide-assists/src/handlers/extract_function.rs5
-rw-r--r--crates/ide-db/src/syntax_helpers/node_ext.rs22
-rw-r--r--crates/ide/src/syntax_highlighting.rs136
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs353
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_asm.html33
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html9
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_const.html21
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html9
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_general.html9
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_macros.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_operators.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html7
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_strings.html11
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html95
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs76
-rw-r--r--docs/book/src/assists_generated.md6
37 files changed, 547 insertions, 537 deletions
diff --git a/crates/hir-ty/src/diagnostics.rs b/crates/hir-ty/src/diagnostics.rs
index 30c02a2936..845d333335 100644
--- a/crates/hir-ty/src/diagnostics.rs
+++ b/crates/hir-ty/src/diagnostics.rs
@@ -9,5 +9,8 @@ pub use crate::diagnostics::{
expr::{
record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
},
- unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason},
+ unsafe_check::{
+ missing_unsafe, unsafe_operations, unsafe_operations_for_body, InsideUnsafeBlock,
+ UnsafetyReason,
+ },
};
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index ac849b0762..d2b908839c 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -95,7 +95,26 @@ enum UnsafeDiagnostic {
DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock },
}
-pub fn unsafe_expressions(
+pub fn unsafe_operations_for_body(
+ db: &dyn HirDatabase,
+ infer: &InferenceResult,
+ def: DefWithBodyId,
+ body: &Body,
+ callback: &mut dyn FnMut(ExprOrPatId),
+) {
+ let mut visitor_callback = |diag| {
+ if let UnsafeDiagnostic::UnsafeOperation { node, .. } = diag {
+ callback(node);
+ }
+ };
+ let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback);
+ visitor.walk_expr(body.body_expr);
+ for &param in &body.params {
+ visitor.walk_pat(param);
+ }
+}
+
+pub fn unsafe_operations(
db: &dyn HirDatabase,
infer: &InferenceResult,
def: DefWithBodyId,
@@ -281,13 +300,6 @@ impl<'a> UnsafeVisitor<'a> {
self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref);
}
}
- Expr::Unsafe { .. } => {
- let old_inside_unsafe_block =
- mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
- self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
- self.inside_unsafe_block = old_inside_unsafe_block;
- return;
- }
&Expr::Assignment { target, value: _ } => {
let old_inside_assignment = mem::replace(&mut self.inside_assignment, true);
self.walk_pats_top(std::iter::once(target), current);
@@ -306,6 +318,20 @@ impl<'a> UnsafeVisitor<'a> {
}
}
}
+ Expr::Unsafe { statements, .. } => {
+ let old_inside_unsafe_block =
+ mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
+ self.walk_pats_top(
+ statements.iter().filter_map(|statement| match statement {
+ &Statement::Let { pat, .. } => Some(pat),
+ _ => None,
+ }),
+ current,
+ );
+ self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
+ self.inside_unsafe_block = old_inside_unsafe_block;
+ return;
+ }
Expr::Block { statements, .. } | Expr::Async { statements, .. } => {
self.walk_pats_top(
statements.iter().filter_map(|statement| match statement {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index bb67fa63a1..1b8531209c 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -12,6 +12,7 @@ use std::{
use either::Either;
use hir_def::{
+ expr_store::ExprOrPatSource,
hir::{Expr, ExprOrPatId},
lower::LowerCtx,
nameres::{MacroSubNs, ModuleOrigin},
@@ -30,6 +31,7 @@ use hir_expand::{
name::AsName,
ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
};
+use hir_ty::diagnostics::unsafe_operations_for_body;
use intern::{sym, Symbol};
use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet};
@@ -48,8 +50,8 @@ use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
- Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
- ConstParam, Crate, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
+ Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam,
+ Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
HirFileId, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait,
TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
@@ -1555,6 +1557,19 @@ impl<'db> SemanticsImpl<'db> {
.matched_arm
}
+ pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
+ let def = DefWithBodyId::from(def);
+ let (body, source_map) = self.db.body_with_source_map(def);
+ let infer = self.db.infer(def);
+ let mut res = FxHashSet::default();
+ unsafe_operations_for_body(self.db, &infer, def, &body, &mut |node| {
+ if let Ok(node) = source_map.expr_or_pat_syntax(node) {
+ res.insert(node);
+ }
+ });
+ res
+ }
+
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
if mac.is_asm_or_global_asm(self.db) {
@@ -1682,6 +1697,15 @@ impl<'db> SemanticsImpl<'db> {
Some(res)
}
+ pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
+ let container = self.with_ctx(|ctx| ctx.find_container(node))?;
+
+ match container {
+ ChildContainer::DefWithBodyId(def) => Some(def.into()),
+ _ => None,
+ }
+ }
+
/// Returns none if the file of the node is not part of a crate.
fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
let node = self.find_file(node);
@@ -1783,91 +1807,6 @@ impl<'db> SemanticsImpl<'db> {
InFile::new(file_id, node)
}
- pub fn is_unsafe_method_call(&self, method_call_expr: &ast::MethodCallExpr) -> bool {
- method_call_expr
- .receiver()
- .and_then(|expr| {
- let field_expr = match expr {
- ast::Expr::FieldExpr(field_expr) => field_expr,
- _ => return None,
- };
- let ty = self.type_of_expr(&field_expr.expr()?)?.original;
- if !ty.is_packed(self.db) {
- return None;
- }
-
- let func = self.resolve_method_call(method_call_expr)?;
- let res = match func.self_param(self.db)?.access(self.db) {
- Access::Shared | Access::Exclusive => true,
- Access::Owned => false,
- };
- Some(res)
- })
- .unwrap_or(false)
- }
-
- pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
- ref_expr
- .expr()
- .and_then(|expr| {
- let field_expr = match expr {
- ast::Expr::FieldExpr(field_expr) => field_expr,
- _ => return None,
- };
- let expr = field_expr.expr()?;
- self.type_of_expr(&expr)
- })
- // Binding a reference to a packed type is possibly unsafe.
- .map(|ty| ty.original.is_packed(self.db))
- .unwrap_or(false)
-
- // FIXME This needs layout computation to be correct. It will highlight
- // more than it should with the current implementation.
- }
-
- pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
- if ident_pat.ref_token().is_none() {
- return false;
- }
-
- ident_pat
- .syntax()
- .parent()
- .and_then(|parent| {
- // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
- // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
- // so this tries to lookup the `IdentPat` anywhere along that structure to the
- // `RecordPat` so we can get the containing type.
- let record_pat = ast::RecordPatField::cast(parent.clone())
- .and_then(|record_pat| record_pat.syntax().parent())
- .or_else(|| Some(parent.clone()))
- .and_then(|parent| {
- ast::RecordPatFieldList::cast(parent)?
- .syntax()
- .parent()
- .and_then(ast::RecordPat::cast)
- });
-
- // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
- // this is initialized from a `FieldExpr`.
- if let Some(record_pat) = record_pat {
- self.type_of_pat(&ast::Pat::RecordPat(record_pat))
- } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
- let field_expr = match let_stmt.initializer()? {
- ast::Expr::FieldExpr(field_expr) => field_expr,
- _ => return None,
- };
-
- self.type_of_expr(&field_expr.expr()?)
- } else {
- None
- }
- })
- // Binding a reference to a packed type is possibly unsafe.
- .map(|ty| ty.original.is_packed(self.db))
- .unwrap_or(false)
- }
-
/// Returns `true` if the `node` is inside an `unsafe` context.
pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
let Some(enclosing_item) =
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 9019863f7f..d1245f5f7d 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -35,7 +35,7 @@ use hir_expand::{
};
use hir_ty::{
diagnostics::{
- record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
+ record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations,
InsideUnsafeBlock,
},
from_assoc_type_id,
@@ -1160,7 +1160,7 @@ impl SourceAnalyzer {
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
let mut is_unsafe = false;
let mut walk_expr = |expr_id| {
- unsafe_expressions(db, infer, *def, body, expr_id, &mut |inside_unsafe_block| {
+ unsafe_operations(db, infer, *def, body, expr_id, &mut |inside_unsafe_block| {
is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
})
};
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 751e4a5a57..330587e0db 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -750,7 +750,10 @@ impl FunctionBody {
ast::Stmt::Item(_) => (),
ast::Stmt::LetStmt(stmt) => {
if let Some(pat) = stmt.pat() {
- walk_pat(&pat, cb);
+ walk_pat(&pat, &mut |pat| {
+ cb(pat);
+ std::ops::ControlFlow::<(), ()>::Continue(())
+ });
}
if let Some(expr) = stmt.initializer() {
walk_patterns_in_expr(&expr, cb);
diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs
index 74c0b8e2ba..0b2e8aa683 100644
--- a/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -1,4 +1,6 @@
//! Various helper functions to work with SyntaxNodes.
+use std::ops::ControlFlow;
+
use itertools::Itertools;
use parser::T;
use span::Edition;
@@ -119,7 +121,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
match ast::Stmt::cast(node.clone()) {
Some(ast::Stmt::LetStmt(l)) => {
if let Some(pat) = l.pat() {
- walk_pat(&pat, cb);
+ walk_pat(&pat, &mut |pat| {
+ cb(pat);
+ ControlFlow::<(), ()>::Continue(())
+ });
}
if let Some(expr) = l.initializer() {
walk_patterns_in_expr(&expr, cb);
@@ -154,7 +159,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
}
} else if let Some(pat) = ast::Pat::cast(node) {
preorder.skip_subtree();
- walk_pat(&pat, cb);
+ walk_pat(&pat, &mut |pat| {
+ cb(pat);
+ ControlFlow::<(), ()>::Continue(())
+ });
}
}
}
@@ -162,7 +170,10 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
}
/// Preorder walk all the pattern's sub patterns.
-pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
+pub fn walk_pat<T>(
+ pat: &ast::Pat,
+ cb: &mut dyn FnMut(ast::Pat) -> ControlFlow<T>,
+) -> ControlFlow<T> {
let mut preorder = pat.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
@@ -173,10 +184,10 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
match ast::Pat::cast(node) {
Some(pat @ ast::Pat::ConstBlockPat(_)) => {
preorder.skip_subtree();
- cb(pat);
+ cb(pat)?;
}
Some(pat) => {
- cb(pat);
+ cb(pat)?;
}
// skip const args
None if ast::GenericArg::can_cast(kind) => {
@@ -185,6 +196,7 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
None => (),
}
}
+ ControlFlow::Continue(())
}
/// Preorder walk all the type's sub types.
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 519133e3ad..62dc92feb1 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -14,8 +14,11 @@ mod tests;
use std::ops::ControlFlow;
-use hir::{HirFileIdExt, InFile, InRealFile, MacroFileIdExt, MacroKind, Name, Semantics};
-use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind};
+use either::Either;
+use hir::{
+ DefWithBody, HirFileIdExt, InFile, InRealFile, MacroFileIdExt, MacroKind, Name, Semantics,
+};
+use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
use span::EditionedFileId;
use syntax::{
ast::{self, IsString},
@@ -232,7 +235,6 @@ fn traverse(
range_to_highlight: TextRange,
) {
let is_unlinked = sema.file_to_module_def(file_id).is_none();
- let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
enum AttrOrDerive {
Attr(ast::Item),
@@ -247,13 +249,22 @@ fn traverse(
}
}
+ let empty = FxHashSet::default();
+
+ // FIXME: accommodate range highlighting
let mut tt_level = 0;
+ // FIXME: accommodate range highlighting
let mut attr_or_derive_item = None;
// FIXME: these are not perfectly accurate, we determine them by the real file's syntax tree
// an attribute nested in a macro call will not emit `inside_attribute`
let mut inside_attribute = false;
+ // FIXME: accommodate range highlighting
+ let mut body_stack: Vec<Option<DefWithBody>> = vec![];
+ let mut per_body_cache: FxHashMap<DefWithBody, (FxHashSet<_>, FxHashMap<Name, u32>)> =
+ FxHashMap::default();
+
// Walk all nodes, keeping track of whether we are inside a macro or not.
// If in macro, expand it first and highlight the expanded code.
let mut preorder = root.preorder_with_tokens();
@@ -282,48 +293,68 @@ fn traverse(
Leave(NodeOrToken::Node(node)) if ast::Attr::can_cast(node.kind()) => {
inside_attribute = false
}
-
Enter(NodeOrToken::Node(node)) => {
- if let Some(item) = ast::Item::cast(node.clone()) {
+ if let Some(item) = <Either<ast::Item, ast::Variant>>::cast(node.clone()) {
match item {
- ast::Item::Fn(_) | ast::Item::Const(_) | ast::Item::Static(_) => {
- bindings_shadow_count.clear()
- }
- _ => (),
- }
-
- if attr_or_derive_item.is_none() {
- if sema.is_attr_macro_call(InFile::new(file_id.into(), &item)) {
- attr_or_derive_item = Some(AttrOrDerive::Attr(item));
- } else {
- let adt = match item {
- ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
- ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
- ast::Item::Union(it) => Some(ast::Adt::Union(it)),
- _ => None,
- };
- match adt {
- Some(adt)
- if sema
- .is_derive_annotated(InFile::new(file_id.into(), &adt)) =>
- {
- attr_or_derive_item =
- Some(AttrOrDerive::Derive(ast::Item::from(adt)));
+ Either::Left(item) => {
+ match &item {
+ ast::Item::Fn(it) => {
+ body_stack.push(sema.to_def(it).map(Into::into))
+ }
+ ast::Item::Const(it) => {
+ body_stack.push(sema.to_def(it).map(Into::into))
+ }
+ ast::Item::Static(it) => {
+ body_stack.push(sema.to_def(it).map(Into::into))
}
_ => (),
}
+
+ if attr_or_derive_item.is_none() {
+ if sema.is_attr_macro_call(InFile::new(file_id.into(), &item)) {
+ attr_or_derive_item = Some(AttrOrDerive::Attr(item));
+ } else {
+ let adt = match item {
+ ast::Item::Enum(it) => Some(ast::Adt::Enum(it)),
+ ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
+ ast::Item::Union(it) => Some(ast::Adt::Union(it)),
+ _ => None,
+ };
+ match adt {
+ Some(adt)
+ if sema.is_derive_annotated(InFile::new(
+ file_id.into(),
+ &adt,
+ )) =>
+ {
+ attr_or_derive_item =
+ Some(AttrOrDerive::Derive(ast::Item::from(adt)));
+ }
+ _ => (),
+ }
+ }
+ }
}
+ Either::Right(it) => body_stack.push(sema.to_def(&it).map(Into::into)),
}
}
}
- Leave(NodeOrToken::Node(node)) if ast::Item::can_cast(node.kind()) => {
+ Leave(NodeOrToken::Node(node))
+ if <Either<ast::Item, ast::Variant>>::can_cast(node.kind()) =>
+ {
match ast::Item::cast(node.clone()) {
- Some(item)
- if attr_or_derive_item.as_ref().is_some_and(|it| *it.item() == item) =>
- {
- attr_or_derive_item = None;
+ Some(item) => {
+ if attr_or_derive_item.as_ref().is_some_and(|it| *it.item() == item) {
+ attr_or_derive_item = None;
+ }
+ if matches!(
+ item,
+ ast::Item::Fn(_) | ast::Item::Const(_) | ast::Item::Static(_)
+ ) {
+ body_stack.pop();
+ }
}
- _ => (),
+ None => _ = body_stack.pop(),
}
}
_ => (),
@@ -361,16 +392,22 @@ fn traverse(
None => false,
};
- let descended_element = if in_macro {
+ let (descended_element, current_body) = match element {
// Attempt to descend tokens into macro-calls.
- match element {
- NodeOrToken::Token(token) => descend_token(sema, InRealFile::new(file_id, token)),
- n => InFile::new(file_id.into(), n),
+ NodeOrToken::Token(token) if in_macro => {
+ let descended = descend_token(sema, InRealFile::new(file_id, token));
+ let body = match &descended.value {
+ NodeOrToken::Node(n) => {
+ sema.body_for(InFile::new(descended.file_id, n.syntax()))
+ }
+ NodeOrToken::Token(t) => {
+ t.parent().and_then(|it| sema.body_for(InFile::new(descended.file_id, &it)))
+ }
+ };
+ (descended, body)
}
- } else {
- InFile::new(file_id.into(), element)
+ n => (InFile::new(file_id.into(), n), body_stack.last().copied().flatten()),
};
-
// string highlight injections
if let (Some(original_token), Some(descended_token)) =
(original_token, descended_element.value.as_token())
@@ -390,12 +427,24 @@ fn traverse(
}
let edition = descended_element.file_id.edition(sema.db);
+ let (unsafe_ops, bindings_shadow_count) = match current_body {
+ Some(current_body) => {
+ let (ops, bindings) = per_body_cache
+ .entry(current_body)
+ .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default()));
+ (&*ops, Some(bindings))
+ }
+ None => (&empty, None),
+ };
+ let is_unsafe_node =
+ |node| unsafe_ops.contains(&InFile::new(descended_element.file_id, node));
let element = match descended_element.value {
NodeOrToken::Node(name_like) => {
let hl = highlight::name_like(
sema,
krate,
- &mut bindings_shadow_count,
+ bindings_shadow_count,
+ &is_unsafe_node,
config.syntactic_name_ref_highlighting,
name_like,
edition,
@@ -408,7 +457,8 @@ fn traverse(
hl
}
NodeOrToken::Token(token) => {
- highlight::token(sema, token, edition, tt_level > 0).zip(Some(None))
+ highlight::token(sema, token, edition, &is_unsafe_node, tt_level > 0)
+ .zip(Some(None))
}
};
if let Some((mut highlight, binding_hash)) = element {
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index c63043621c..cc02aff2ac 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -41,7 +41,7 @@ pub(super) fn highlight_format_string(
if let Some(res) = res {
stack.add(HlRange {
range,
- highlight: highlight_def(sema, krate, Definition::from(res), edition),
+ highlight: highlight_def(sema, krate, Definition::from(res), edition, true),
binding_hash: None,
})
}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 127861a04b..282fbb4433 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,17 +1,20 @@
//! Computes color for a single element.
+use std::ops::ControlFlow;
+
use either::Either;
use hir::{AsAssocItem, HasVisibility, MacroFileIdExt, Semantics};
use ide_db::{
defs::{Definition, IdentClass, NameClass, NameRefClass},
+ syntax_helpers::node_ext::walk_pat,
FxHashMap, RootDatabase, SymbolKind,
};
use span::Edition;
use stdx::hash_once;
use syntax::{
- ast, match_ast, AstNode, AstToken, NodeOrToken,
+ ast, match_ast, AstNode, AstPtr, AstToken, NodeOrToken,
SyntaxKind::{self, *},
- SyntaxNode, SyntaxToken, T,
+ SyntaxNode, SyntaxNodePtr, SyntaxToken, T,
};
use crate::{
@@ -23,6 +26,7 @@ pub(super) fn token(
sema: &Semantics<'_, RootDatabase>,
token: SyntaxToken,
edition: Edition,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
in_tt: bool,
) -> Option<Highlight> {
if let Some(comment) = ast::Comment::cast(token.clone()) {
@@ -33,11 +37,8 @@ pub(super) fn token(
});
}
- let highlight: Highlight = match token.kind() {
+ let h = match token.kind() {
STRING | BYTE_STRING | C_STRING => HlTag::StringLiteral.into(),
- INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => {
- SymbolKind::Field.into()
- }
INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
BYTE => HlTag::ByteLiteral.into(),
CHAR => HlTag::CharLiteral.into(),
@@ -46,24 +47,25 @@ pub(super) fn token(
// that were not mapped down into macro invocations
HlTag::None.into()
}
- p if p.is_punct() => punctuation(sema, token, p),
+ p if p.is_punct() => punctuation(sema, token, p, is_unsafe_node),
k if k.is_keyword(edition) => {
if in_tt && token.prev_token().is_some_and(|t| t.kind() == T![$]) {
// we are likely within a macro definition where our keyword is a fragment name
HlTag::None.into()
} else {
- keyword(sema, token, k)?
+ keyword(token, k)
}
}
_ => return None,
};
- Some(highlight)
+ Some(h)
}
pub(super) fn name_like(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
- bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+ bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
syntactic_name_ref_highlighting: bool,
name_like: ast::NameLike,
edition: Edition,
@@ -75,19 +77,26 @@ pub(super) fn name_like(
krate,
bindings_shadow_count,
&mut binding_hash,
+ is_unsafe_node,
syntactic_name_ref_highlighting,
name_ref,
edition,
),
- ast::NameLike::Name(name) => {
- highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name, edition)
- }
+ ast::NameLike::Name(name) => highlight_name(
+ sema,
+ bindings_shadow_count,
+ &mut binding_hash,
+ is_unsafe_node,
+ krate,
+ name,
+ edition,
+ ),
ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
Some(IdentClass::NameClass(NameClass::Definition(def))) => {
- highlight_def(sema, krate, def, edition) | HlMod::Definition
+ highlight_def(sema, krate, def, edition, false) | HlMod::Definition
}
Some(IdentClass::NameRefClass(NameRefClass::Definition(def, _))) => {
- highlight_def(sema, krate, def, edition)
+ highlight_def(sema, krate, def, edition, true)
}
// FIXME: Fallback for '_, as we do not resolve these yet
_ => SymbolKind::LifetimeParam.into(),
@@ -100,44 +109,49 @@ fn punctuation(
sema: &Semantics<'_, RootDatabase>,
token: SyntaxToken,
kind: SyntaxKind,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
) -> Highlight {
- let parent = token.parent();
- let parent_kind = parent.as_ref().map_or(EOF, SyntaxNode::kind);
- match (kind, parent_kind) {
+ let operator_parent = token.parent();
+ let parent_kind = operator_parent.as_ref().map_or(EOF, SyntaxNode::kind);
+ let h = match (kind, parent_kind) {
(T![?], TRY_EXPR) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
(T![&], BIN_EXPR) => HlOperator::Bitwise.into(),
- (T![&], REF_EXPR) => {
- let h = HlTag::Operator(HlOperator::Other).into();
- let is_unsafe = parent
- .and_then(ast::RefExpr::cast)
- .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr));
- if let Some(true) = is_unsafe {
- h | HlMod::Unsafe
+ (T![&], REF_EXPR | REF_PAT) => HlTag::Operator(HlOperator::Other).into(),
+ (T![..] | T![..=], _) => match token.parent().and_then(ast::Pat::cast) {
+ Some(pat) if is_unsafe_node(AstPtr::new(&pat).wrap_right()) => {
+ Highlight::from(HlOperator::Other) | HlMod::Unsafe
+ }
+ _ => HlOperator::Other.into(),
+ },
+ (T![::] | T![->] | T![=>] | T![=] | T![@] | T![.], _) => HlOperator::Other.into(),
+ (T![!], MACRO_CALL) => {
+ if operator_parent
+ .and_then(ast::MacroCall::cast)
+ .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call))
+ {
+ Highlight::from(HlPunct::MacroBang) | HlMod::Unsafe
} else {
- h
+ HlPunct::MacroBang.into()
}
}
- (T![::] | T![->] | T![=>] | T![..] | T![..=] | T![=] | T![@] | T![.], _) => {
- HlOperator::Other.into()
- }
- (T![!], MACRO_CALL | MACRO_RULES) => HlPunct::MacroBang.into(),
+ (T![!], MACRO_RULES) => HlPunct::MacroBang.into(),
(T![!], NEVER_TYPE) => HlTag::BuiltinType.into(),
(T![!], PREFIX_EXPR) => HlOperator::Logical.into(),
(T![*], PTR_TYPE) => HlTag::Keyword.into(),
(T![*], PREFIX_EXPR) => {
- let is_raw_ptr = (|| {
- let prefix_expr = parent.and_then(ast::PrefixExpr::cast)?;
- let expr = prefix_expr.expr()?;
- sema.type_of_expr(&expr)?.original.is_raw_ptr().then_some(())
- })();
- if let Some(()) = is_raw_ptr {
- HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
+ let h = HlTag::Operator(HlOperator::Other).into();
+ let ptr = operator_parent
+ .as_ref()
+ .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)));
+ if ptr.is_some_and(is_unsafe_node) {
+ h | HlMod::Unsafe
} else {
- HlOperator::Other.into()
+ h
}
}
(T![-], PREFIX_EXPR) => {
- let prefix_expr = parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
+ let prefix_expr =
+ operator_parent.and_then(ast::PrefixExpr::cast).and_then(|e| e.expr());
match prefix_expr {
Some(ast::Expr::Literal(_)) => HlTag::NumericLiteral,
_ => HlTag::Operator(HlOperator::Other),
@@ -157,36 +171,90 @@ fn punctuation(
HlOperator::Comparison.into()
}
(_, ATTR) => HlTag::AttributeBracket.into(),
+ (T![>], _)
+ if operator_parent
+ .as_ref()
+ .and_then(SyntaxNode::parent)
+ .is_some_and(|it| it.kind() == MACRO_RULES) =>
+ {
+ HlOperator::Other.into()
+ }
(kind, _) => match kind {
- T!['['] | T![']'] => HlPunct::Bracket,
- T!['{'] | T!['}'] => HlPunct::Brace,
- T!['('] | T![')'] => HlPunct::Parenthesis,
- T![>]
- if parent
+ T!['['] | T![']'] => {
+ let is_unsafe_macro = operator_parent
.as_ref()
- .and_then(SyntaxNode::parent)
- .is_some_and(|it| it.kind() == MACRO_RULES) =>
- {
- return HlOperator::Other.into()
+ .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+ .and_then(ast::MacroCall::cast)
+ .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+ let is_unsafe = is_unsafe_macro
+ || operator_parent
+ .as_ref()
+ .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)))
+ .is_some_and(is_unsafe_node);
+ if is_unsafe {
+ return Highlight::from(HlPunct::Bracket) | HlMod::Unsafe;
+ } else {
+ HlPunct::Bracket
+ }
+ }
+ T!['{'] | T!['}'] => {
+ let is_unsafe_macro = operator_parent
+ .as_ref()
+ .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+ .and_then(ast::MacroCall::cast)
+ .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+ let is_unsafe = is_unsafe_macro
+ || operator_parent
+ .as_ref()
+ .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)))
+ .is_some_and(is_unsafe_node);
+ if is_unsafe {
+ return Highlight::from(HlPunct::Brace) | HlMod::Unsafe;
+ } else {
+ HlPunct::Brace
+ }
+ }
+ T!['('] | T![')'] => {
+ let is_unsafe_macro = operator_parent
+ .as_ref()
+ .and_then(|it| ast::TokenTree::cast(it.clone())?.syntax().parent())
+ .and_then(ast::MacroCall::cast)
+ .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+ let is_unsafe = is_unsafe_macro
+ || operator_parent
+ .and_then(|it| {
+ if ast::ArgList::can_cast(it.kind()) {
+ it.parent()
+ } else {
+ Some(it)
+ }
+ })
+ .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(&it)))
+ .is_some_and(is_unsafe_node);
+
+ if is_unsafe {
+ return Highlight::from(HlPunct::Parenthesis) | HlMod::Unsafe;
+ } else {
+ HlPunct::Parenthesis
+ }
}
T![<] | T![>] => HlPunct::Angle,
- T![,] => HlPunct::Comma,
+ // Early return as otherwise we'd highlight these in
+ // asm expressions
+ T![,] => return HlPunct::Comma.into(),
T![:] => HlPunct::Colon,
T![;] => HlPunct::Semi,
T![.] => HlPunct::Dot,
_ => HlPunct::Other,
}
.into(),
- }
+ };
+ h
}
-fn keyword(
- sema: &Semantics<'_, RootDatabase>,
- token: SyntaxToken,
- kind: SyntaxKind,
-) -> Option<Highlight> {
+fn keyword(token: SyntaxToken, kind: SyntaxKind) -> Highlight {
let h = Highlight::new(HlTag::Keyword);
- let h = match kind {
+ match kind {
T![await] => h | HlMod::Async | HlMod::ControlFlow,
T![async] => h | HlMod::Async,
T![break]
@@ -202,53 +270,33 @@ fn keyword(
T![do] | T![yeet] if parent_matches::<ast::YeetExpr>(&token) => h | HlMod::ControlFlow,
T![for] if parent_matches::<ast::ForExpr>(&token) => h | HlMod::ControlFlow,
T![unsafe] => h | HlMod::Unsafe,
- T![const]
- if token.parent().is_some_and(|it| {
- matches!(
- it.kind(),
- SyntaxKind::CONST
- | SyntaxKind::FN
- | SyntaxKind::IMPL
- | SyntaxKind::BLOCK_EXPR
- | SyntaxKind::CLOSURE_EXPR
- | SyntaxKind::FN_PTR_TYPE
- | SyntaxKind::TYPE_BOUND
- | SyntaxKind::CONST_BLOCK_PAT
- )
- }) =>
- {
- h | HlMod::Const
- }
+ T![const] => h | HlMod::Const,
T![true] | T![false] => HlTag::BoolLiteral.into(),
// crate is handled just as a token if it's in an `extern crate`
T![crate] if parent_matches::<ast::ExternCrate>(&token) => h,
- T![ref] => match token.parent().and_then(ast::IdentPat::cast) {
- Some(ident) if sema.is_unsafe_ident_pat(&ident) => h | HlMod::Unsafe,
- _ => h,
- },
_ => h,
- };
- Some(h)
+ }
}
fn highlight_name_ref(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
- bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+ bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
binding_hash: &mut Option<u64>,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
syntactic_name_ref_highlighting: bool,
name_ref: ast::NameRef,
edition: Edition,
) -> Highlight {
let db = sema.db;
- if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref, edition) {
+ if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref, is_unsafe_node) {
return res;
}
let name_class = match NameRefClass::classify(sema, &name_ref) {
Some(name_kind) => name_kind,
None if syntactic_name_ref_highlighting => {
- return highlight_name_ref_by_syntax(name_ref, sema, krate, edition)
+ return highlight_name_ref_by_syntax(name_ref, sema, krate, is_unsafe_node)
}
// FIXME: This is required for helper attributes used by proc-macros, as those do not map down
// to anything when used.
@@ -267,17 +315,20 @@ fn highlight_name_ref(
let mut h = match name_class {
NameRefClass::Definition(def, _) => {
if let Definition::Local(local) = &def {
- let name = local.name(db);
- let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
- *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+ if let Some(bindings_shadow_count) = bindings_shadow_count {
+ let name = local.name(sema.db);
+ let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+ *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+ }
};
- let mut h = highlight_def(sema, krate, def, edition);
+ let mut h = highlight_def(sema, krate, def, edition, true);
match def {
Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => {
h |= HlMod::Consuming;
}
+ // highlight unsafe traits as unsafe only in their implementations
Definition::Trait(trait_) if trait_.is_unsafe(db) => {
if ast::Impl::for_trait_name_ref(&name_ref)
.is_some_and(|impl_| impl_.unsafe_token().is_some())
@@ -285,23 +336,66 @@ fn highlight_name_ref(
h |= HlMod::Unsafe;
}
}
- Definition::Field(field) => {
- if let Some(parent) = name_ref.syntax().parent() {
- if matches!(parent.kind(), FIELD_EXPR | RECORD_PAT_FIELD) {
- if let hir::VariantDef::Union(_) = field.parent_def(db) {
- h |= HlMod::Unsafe;
- }
- }
+ Definition::Function(_) => {
+ let is_unsafe = name_ref
+ .syntax()
+ .parent()
+ .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+ .and_then(ast::PathExpr::cast)
+ .and_then(|it| it.syntax().parent())
+ .and_then(ast::CallExpr::cast)
+ .is_some_and(|it| {
+ is_unsafe_node(AstPtr::new(&ast::Expr::CallExpr(it)).wrap_left())
+ });
+ if is_unsafe {
+ h |= HlMod::Unsafe;
}
}
Definition::Macro(_) => {
- if let Some(macro_call) =
- ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
- .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
- {
- if sema.is_unsafe_macro_call(&macro_call) {
- h |= HlMod::Unsafe;
- }
+ let is_unsafe = name_ref
+ .syntax()
+ .parent()
+ .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+ .and_then(ast::MacroCall::cast)
+ .is_some_and(|macro_call| sema.is_unsafe_macro_call(&macro_call));
+ if is_unsafe {
+ h |= HlMod::Unsafe;
+ }
+ }
+ Definition::Field(_) => {
+ let is_unsafe = name_ref
+ .syntax()
+ .parent()
+ .and_then(|it| {
+ match_ast! { match it {
+ ast::FieldExpr(expr) => Some(is_unsafe_node(AstPtr::new(&Either::Left(expr.into())))),
+ ast::RecordPatField(pat) => {
+ walk_pat(&pat.pat()?, &mut |pat| {
+ if is_unsafe_node(AstPtr::new(&Either::Right(pat))) {
+ ControlFlow::Break(true)
+ }
+ else {ControlFlow::Continue(())}
+ }).break_value()
+ },
+ _ => None,
+ }}
+ })
+ .unwrap_or(false);
+ if is_unsafe {
+ h |= HlMod::Unsafe;
+ }
+ }
+ Definition::Static(_) => {
+ let is_unsafe = name_ref
+ .syntax()
+ .parent()
+ .and_then(|it| ast::PathSegment::cast(it)?.parent_path().syntax().parent())
+ .and_then(ast::PathExpr::cast)
+ .is_some_and(|it| {
+ is_unsafe_node(AstPtr::new(&ast::Expr::PathExpr(it)).wrap_left())
+ });
+ if is_unsafe {
+ h |= HlMod::Unsafe;
}
}
_ => (),
@@ -310,7 +404,7 @@ fn highlight_name_ref(
h
}
NameRefClass::FieldShorthand { field_ref, .. } => {
- highlight_def(sema, krate, field_ref.into(), edition)
+ highlight_def(sema, krate, field_ref.into(), edition, true)
}
NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => {
let mut h = HlTag::Symbol(SymbolKind::Module).into();
@@ -342,22 +436,25 @@ fn highlight_name_ref(
fn highlight_name(
sema: &Semantics<'_, RootDatabase>,
- bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
+ bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
binding_hash: &mut Option<u64>,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
krate: hir::Crate,
name: ast::Name,
edition: Edition,
) -> Highlight {
let name_kind = NameClass::classify(sema, &name);
if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
- let name = local.name(sema.db);
- let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
- *shadow_count += 1;
- *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+ if let Some(bindings_shadow_count) = bindings_shadow_count {
+ let name = local.name(sema.db);
+ let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
+ *shadow_count += 1;
+ *binding_hash = Some(calc_binding_hash(&name, *shadow_count))
+ }
};
match name_kind {
Some(NameClass::Definition(def)) => {
- let mut h = highlight_def(sema, krate, def, edition) | HlMod::Definition;
+ let mut h = highlight_def(sema, krate, def, edition, false) | HlMod::Definition;
if let Definition::Trait(trait_) = &def {
if trait_.is_unsafe(sema.db) {
h |= HlMod::Unsafe;
@@ -365,10 +462,14 @@ fn highlight_name(
}
h
}
- Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def, edition),
- Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
+ Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def, edition, true),
+ Some(NameClass::PatFieldShorthand { .. }) => {
let mut h = HlTag::Symbol(SymbolKind::Field).into();
- if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) {
+ let is_unsafe =
+ name.syntax().parent().and_then(ast::IdentPat::cast).is_some_and(|it| {
+ is_unsafe_node(AstPtr::new(&ast::Pat::IdentPat(it)).wrap_right())
+ });
+ if is_unsafe {
h |= HlMod::Unsafe;
}
h
@@ -386,6 +487,7 @@ pub(super) fn highlight_def(
krate: hir::Crate,
def: Definition,
edition: Edition,
+ is_ref: bool,
) -> Highlight {
let db = sema.db;
let mut h = match def {
@@ -439,7 +541,7 @@ pub(super) fn highlight_def(
// We probably should consider checking the current function, but I found no easy way to do
// that (also I'm worried about perf). There's also an instance below.
// FIXME: This should be the edition of the call.
- if func.is_unsafe_to_call(db, None, edition) {
+ if !is_ref && func.is_unsafe_to_call(db, None, edition) {
h |= HlMod::Unsafe;
}
if func.is_async(db) {
@@ -509,7 +611,9 @@ pub(super) fn highlight_def(
if s.is_mut(db) {
h |= HlMod::Mutable;
- h |= HlMod::Unsafe;
+ if !is_ref {
+ h |= HlMod::Unsafe;
+ }
}
h
@@ -587,23 +691,24 @@ fn highlight_method_call_by_name_ref(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
name_ref: &ast::NameRef,
- edition: Edition,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
) -> Option<Highlight> {
let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
- highlight_method_call(sema, krate, &mc, edition)
+ highlight_method_call(sema, krate, &mc, is_unsafe_node)
}
fn highlight_method_call(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
method_call: &ast::MethodCallExpr,
- edition: Edition,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
) -> Option<Highlight> {
let func = sema.resolve_method_call(method_call)?;
let mut h = SymbolKind::Method.into();
- if func.is_unsafe_to_call(sema.db, None, edition) || sema.is_unsafe_method_call(method_call) {
+ let is_unsafe = is_unsafe_node(AstPtr::new(method_call).upcast::<ast::Expr>().wrap_left());
+ if is_unsafe {
h |= HlMod::Unsafe;
}
if func.is_async(sema.db) {
@@ -695,7 +800,7 @@ fn highlight_name_ref_by_syntax(
name: ast::NameRef,
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
- edition: Edition,
+ is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
) -> Highlight {
let default = HlTag::UnresolvedReference;
@@ -707,19 +812,13 @@ fn highlight_name_ref_by_syntax(
match parent.kind() {
EXTERN_CRATE => HlTag::Symbol(SymbolKind::Module) | HlMod::CrateRoot,
METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
- .and_then(|it| highlight_method_call(sema, krate, &it, edition))
+ .and_then(|it| highlight_method_call(sema, krate, &it, is_unsafe_node))
.unwrap_or_else(|| SymbolKind::Method.into()),
FIELD_EXPR => {
let h = HlTag::Symbol(SymbolKind::Field);
- let is_union = ast::FieldExpr::cast(parent)
- .and_then(|field_expr| sema.resolve_field(&field_expr))
- .is_some_and(|field| match field {
- Either::Left(field) => {
- matches!(field.parent_def(sema.db), hir::VariantDef::Union(_))
- }
- Either::Right(_) => false,
- });
- if is_union {
+ let is_unsafe = ast::Expr::cast(parent)
+ .is_some_and(|it| is_unsafe_node(AstPtr::new(&it).wrap_left()));
+ if is_unsafe {
h | HlMod::Unsafe
} else {
h.into()
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 47ad54759a..07d40bafeb 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -88,12 +88,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -115,6 +109,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html b/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
index 2bc22f960b..c8ffa9e855 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -49,26 +44,26 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
<span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">o</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="semicolon">;</span>
- <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
<span class="string_literal macro">"%input = OpLoad _ {</span><span class="variable">0</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
<span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"%result = "</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="string_literal macro">" _ %input"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
<span class="string_literal macro">"OpStore {</span><span class="variable">1</span><span class="string_literal macro">} %result"</span><span class="comma macro">,</span>
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="operator macro">&</span><span class="variable macro">foo</span><span class="comma macro">,</span>
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="operator macro">&</span><span class="keyword macro">mut</span> <span class="variable macro mutable">o</span><span class="comma macro">,</span>
- <span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">thread_id</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
- <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="string_literal macro">"
mov {</span><span class="variable">0</span><span class="string_literal macro">}, gs:[0x30]
mov {</span><span class="variable">0</span><span class="string_literal macro">}, [{</span><span class="variable">0</span><span class="string_literal macro">}+0x48]
- "</span><span class="comma macro">,</span> <span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">thread_id</span><span class="comma macro">,</span> <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">pure</span><span class="comma macro">,</span> <span class="keyword macro">readonly</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+ "</span><span class="comma macro">,</span> <span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">thread_id</span><span class="comma macro">,</span> <span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">pure</span><span class="comma macro">,</span> <span class="keyword macro">readonly</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="keyword">static</span> <span class="static declaration">UNMAP_BASE</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
<span class="keyword const">const</span> <span class="constant const declaration">MEM_RELEASE</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
<span class="keyword">static</span> <span class="static declaration">VirtualFree</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
<span class="keyword const">const</span> <span class="constant const declaration">OffPtr</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
<span class="keyword const">const</span> <span class="constant const declaration">OffFn</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
- <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="string_literal macro">"
push {</span><span class="variable">free_type</span><span class="string_literal macro">}
push {</span><span class="variable">free_size</span><span class="string_literal macro">}
push {</span><span class="variable">base</span><span class="string_literal macro">}
@@ -82,26 +77,26 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
jmp {</span><span class="variable">virtual_free</span><span class="string_literal macro">}
"</span><span class="comma macro">,</span>
- <span class="variable declaration macro">off_ptr</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">OffPtr</span><span class="comma macro">,</span>
- <span class="variable declaration macro">off_fn</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">OffFn</span><span class="comma macro">,</span>
+ <span class="variable declaration macro">off_ptr</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">OffPtr</span><span class="comma macro">,</span>
+ <span class="variable declaration macro">off_fn</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">OffFn</span><span class="comma macro">,</span>
- <span class="variable declaration macro">free_size</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="numeric_literal macro">0</span><span class="comma macro">,</span>
- <span class="variable declaration macro">free_type</span> <span class="operator macro">=</span> <span class="keyword macro">const</span> <span class="constant const macro">MEM_RELEASE</span><span class="comma macro">,</span>
+ <span class="variable declaration macro">free_size</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="numeric_literal macro">0</span><span class="comma macro">,</span>
+ <span class="variable declaration macro">free_type</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="constant const macro">MEM_RELEASE</span><span class="comma macro">,</span>
<span class="variable declaration macro">virtual_free</span> <span class="operator macro">=</span> <span class="keyword macro">sym</span> <span class="static macro">VirtualFree</span><span class="comma macro">,</span>
<span class="variable declaration macro">base</span> <span class="operator macro">=</span> <span class="keyword macro">sym</span> <span class="static macro">UNMAP_BASE</span><span class="comma macro">,</span>
<span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">noreturn</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
- <span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
<span class="brace">}</span>
<span class="comment">// taken from https://github.com/rust-embedded/cortex-m/blob/47921b51f8b960344fcfa1255a50a0d19efcde6d/cortex-m/src/asm.rs#L254-L274</span>
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">inline</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">pub</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration public unsafe">bootstrap</span><span class="parenthesis">(</span><span class="value_param declaration">msp</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">u32</span><span class="comma">,</span> <span class="value_param declaration">rv</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
+<span class="keyword">pub</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration public unsafe">bootstrap</span><span class="parenthesis">(</span><span class="value_param declaration">msp</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">u32</span><span class="comma">,</span> <span class="value_param declaration">rv</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">!</span> <span class="brace">{</span>
<span class="comment">// Ensure thumb mode is set.</span>
<span class="keyword">let</span> <span class="variable declaration">rv</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="value_param">rv</span> <span class="keyword">as</span> <span class="builtin_type">u32</span><span class="parenthesis">)</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">msp</span> <span class="operator">=</span> <span class="value_param">msp</span> <span class="keyword">as</span> <span class="builtin_type">u32</span><span class="semicolon">;</span>
- <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
<span class="string_literal macro">"mrs {</span><span class="variable">tmp</span><span class="string_literal macro">}, CONTROL"</span><span class="comma macro">,</span>
<span class="string_literal macro">"bics {</span><span class="variable">tmp</span><span class="string_literal macro">}, {</span><span class="variable">spsel</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
<span class="string_literal macro">"msr CONTROL, {</span><span class="variable">tmp</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
@@ -115,5 +110,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="variable declaration macro">msp</span> <span class="operator macro">=</span> <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">msp</span><span class="comma macro">,</span>
<span class="variable declaration macro">rv</span> <span class="operator macro">=</span> <span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">rv</span><span class="comma macro">,</span>
<span class="keyword macro">options</span><span class="parenthesis macro">(</span><span class="keyword macro">noreturn</span><span class="comma macro">,</span> <span class="keyword macro">nomem</span><span class="comma macro">,</span> <span class="keyword macro">nostack</span><span class="parenthesis macro">)</span><span class="comma macro">,</span>
- <span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 9c7f03fc15..faace6eaff 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index e1d51dc0b7..d59f4caa97 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
index af29af3f03..3beda396da 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -58,7 +53,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span>
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span>
- <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
+ <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">&gt;</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span>
<span class="brace">}</span>
<span class="brace">}</span>
<span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
index 6d8f6b3c6e..9c7324eafa 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -50,21 +45,21 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
<span class="brace">}</span><span class="semicolon">;</span>
<span class="brace">}</span>
-<span class="keyword const">const</span> <span class="constant const declaration">CONST_ITEM</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-<span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function const declaration">const_fn</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">CONST_PARAM</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="keyword const">const</span> <span class="brace">{</span><span class="brace">}</span><span class="colon">:</span> <span class="keyword">const</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="keyword">where</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="brace">{</span>
+<span class="keyword const">const</span> <span class="constant const declaration">CONST_ITEM</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function const declaration">const_fn</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">CONST_PARAM</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="keyword const">const</span> <span class="brace">{</span><span class="brace">}</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="keyword">where</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword const">const</span> <span class="trait">ConstTrait</span> <span class="brace">{</span>
<span class="constant const">CONST_ITEM</span><span class="semicolon">;</span>
<span class="const_param const">CONST_PARAM</span><span class="semicolon">;</span>
<span class="keyword const">const</span> <span class="brace">{</span>
- <span class="keyword">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span>
+ <span class="keyword const">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span>
<span class="brace">}</span>
<span class="macro public">id</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
<span class="constant const macro">CONST_ITEM</span><span class="semicolon macro">;</span>
<span class="const_param const macro">CONST_PARAM</span><span class="semicolon macro">;</span>
<span class="keyword const macro">const</span> <span class="brace macro">{</span>
- <span class="keyword macro">const</span> <span class="punctuation macro">|</span><span class="punctuation macro">|</span> <span class="brace macro">{</span><span class="brace macro">}</span>
+ <span class="keyword const macro">const</span> <span class="punctuation macro">|</span><span class="punctuation macro">|</span> <span class="brace macro">{</span><span class="brace macro">}</span>
<span class="brace macro">}</span><span class="semicolon macro">;</span>
- <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
- <span class="keyword macro">const</span>
+ <span class="operator macro">&</span><span class="keyword macro">raw</span> <span class="keyword const macro">const</span> <span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon macro">;</span>
+ <span class="keyword const macro">const</span>
<span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="parenthesis">(</span><span class="parenthesis">)</span><span class="operator">.</span><span class="method const consuming trait">assoc_const_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
@@ -80,6 +75,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span>
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
- <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+ <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
<span class="brace">}</span><span class="semicolon">;</span>
<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index 63e1560b92..4613c65ee6 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index dfad3a6605..b1b2c659a2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 263e4545fb..c8c8c5dba4 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -129,7 +124,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="comment documentation">///</span>
<span class="comment documentation">/// ```</span>
<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// functions</span>
- <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param const declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
+ <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword const injected">const</span><span class="none injected"> </span><span class="const_param const declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="none injected"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param const injected">X</span><span class="semicolon injected">;</span>
<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="brace injected">}</span>
<span class="comment documentation">/// ```</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index fe5f5ab6a9..5399f83085 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index eb532a5639..00925bd81e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -109,7 +104,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="keyword control">loop</span> <span class="brace">{</span><span class="brace">}</span>
<span class="brace">}</span>
-<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword">const</span> <span class="const_param const declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
+<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="angle">&lt;</span><span class="keyword const">const</span> <span class="const_param const declaration">FOO</span><span class="colon">:</span> <span class="builtin_type">usize</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="brace">{</span>
<span class="function">const_param</span><span class="operator">::</span><span class="angle">&lt;</span><span class="brace">{</span> <span class="const_param const">FOO</span> <span class="brace">}</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="const_param const">FOO</span>
<span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 1f9422161d..3b468ab6db 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
index a846addba3..5ef64465c9 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
index c3377614d7..0407e6896e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
index 9b22500396..f39d033c76 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
index 9b22500396..f39d033c76 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
index ac8353120e..721185a1a8 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
index 694e54d2fa..b2c82051eb 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index 8428b81580..618ea2171b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index f224435e96..c3145941c3 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
index 947d1bf1e3..9996a87158 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
index 0fe2b6f274..dc9e1de4a4 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index c60b6ab27b..9c42401ed0 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index a4449b5d8d..7f6b4c2c88 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 539c74f6b5..f7d7982080 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -169,12 +164,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="macro public">toho</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
<span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
- <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis">(</span>
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
<span class="string_literal macro">"mov {</span><span class="variable">0</span><span class="string_literal macro">}, {</span><span class="variable">1</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
<span class="string_literal macro">"add {</span><span class="variable">0</span><span class="string_literal macro">}, 5"</span><span class="comma macro">,</span>
<span class="keyword macro">out</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">o</span><span class="comma macro">,</span>
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="reg library macro">reg</span><span class="parenthesis macro">)</span> <span class="variable macro">i</span><span class="comma macro">,</span>
- <span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="keyword const">const</span> <span class="constant const declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span>
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">m</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 9a46d9f402..44905831e3 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -14,12 +14,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.string_literal { color: #CC9393; }
.field { color: #94BFF3; }
.function { color: #93E0E3; }
-.function.unsafe { color: #BC8383; }
-.trait.unsafe { color: #BC8383; }
-.operator.unsafe { color: #BC8383; }
-.mutable.unsafe { color: #BC8383; text-decoration: underline; }
-.keyword.unsafe { color: #BC8383; font-weight: bold; }
-.macro.unsafe { color: #BC8383; }
.parameter { color: #94BFF3; }
.text { color: #DCDCCC; }
.type { color: #7CB8BB; }
@@ -41,6 +35,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
.control { font-style: italic; }
.reference { font-style: italic; font-weight: bold; }
.const { font-weight: bolder; }
+.unsafe { color: #BC8383; }
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
@@ -52,78 +47,82 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="brace">}</span>
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span>
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">&gt;</span> <span class="brace">{</span>
- <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+ <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword const">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
<span class="brace">}</span><span class="semicolon">;</span>
<span class="brace">}</span>
-<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
-<span class="keyword">static</span> <span class="static declaration">GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
-<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">union</span> <span class="union declaration">Union</span> <span class="brace">{</span>
- <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
- <span class="field declaration">b</span><span class="colon">:</span> <span class="builtin_type">f32</span><span class="comma">,</span>
+ <span class="field declaration">field</span><span class="colon">:</span> <span class="builtin_type">u32</span><span class="comma">,</span>
<span class="brace">}</span>
<span class="keyword">struct</span> <span class="struct declaration">Struct</span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="builtin_type">i32</span> <span class="brace">}</span>
+
+<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+
<span class="keyword">impl</span> <span class="struct">Struct</span> <span class="brace">{</span>
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
<span class="brace">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
- <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
-<span class="brace">}</span>
-
<span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">UnsafeTrait</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="struct">Packed</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword unsafe">unsafe</span> <span class="keyword">impl</span> <span class="trait unsafe">UnsafeTrait</span> <span class="keyword">for</span> <span class="union">Union</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">impl</span> <span class="punctuation">!</span><span class="trait">UnsafeTrait</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
<span class="keyword">fn</span> <span class="function declaration">unsafe_trait_bound</span><span class="angle">&lt;</span><span class="type_param declaration">T</span><span class="colon">:</span> <span class="trait">UnsafeTrait</span><span class="angle">&gt;</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="type_param">T</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
-<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
- <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-<span class="brace">}</span>
-
-<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
- <span class="keyword">fn</span> <span class="method associated declaration reference trait">calls_autoref</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+<span class="keyword">extern</span> <span class="brace">{</span>
+ <span class="keyword">static</span> <span class="static declaration">EXTERN_STATIC</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
- <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="variable declaration">x</span><span class="colon">:</span> <span class="keyword">*</span><span class="keyword const">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="variable declaration">u</span><span class="colon">:</span> <span class="union">Union</span><span class="semicolon">;</span>
+ <span class="comment">// id should be safe here, but unsafe_deref should not</span>
<span class="macro public">id</span><span class="macro_bang">!</span> <span class="brace">{</span>
- <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span>
+ <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro unsafe">!</span><span class="parenthesis macro unsafe">(</span><span class="parenthesis macro unsafe">)</span> <span class="brace macro">}</span>
<span class="brace">}</span><span class="semicolon">;</span>
<span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
- <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
- <span class="macro public unsafe">id</span><span class="macro_bang">!</span> <span class="brace">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="comment">// unsafe macro calls</span>
+ <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+ <span class="macro public unsafe">id</span><span class="macro_bang unsafe">!</span> <span class="brace unsafe">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro unsafe">!</span><span class="parenthesis macro unsafe">(</span><span class="parenthesis macro unsafe">)</span> <span class="brace unsafe">}</span><span class="semicolon">;</span>
<span class="comment">// unsafe fn and method calls</span>
- <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
- <span class="keyword control">match</span> <span class="variable">u</span> <span class="brace">{</span>
- <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
- <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">a</span> <span class="brace">}</span> <span class="operator">=&gt;</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="comma">,</span>
- <span class="brace">}</span>
- <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="method reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="function unsafe">unsafe_fn</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+ <span class="self_keyword crate_root public">self</span><span class="operator">::</span><span class="function unsafe">unsafe_fn</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+ <span class="parenthesis">(</span><span class="function">unsafe_fn</span> <span class="keyword">as</span> <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+ <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="operator">.</span><span class="method reference unsafe">unsafe_method</span><span class="parenthesis unsafe">(</span><span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
+
+ <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+ <span class="comment">// this should be safe!</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="punctuation">_</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="comment">// but not these</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="bool_literal">true</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="variable declaration">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="keyword">ref</span> <span class="variable declaration reference">field</span> <span class="brace">}</span><span class="semicolon">;</span>
+ <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field unsafe">field</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="keyword">ref</span> <span class="variable declaration reference">field</span> <span class="punctuation">|</span> <span class="numeric_literal">0</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span>
<span class="comment">// unsafe deref</span>
- <span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
+ <span class="operator unsafe">*</span><span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span><span class="operator">*</span><span class="operator">&</span><span class="operator unsafe">*</span><span class="variable">x</span><span class="semicolon">;</span>
<span class="comment">// unsafe access to a static mut</span>
<span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
- <span class="static">GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
-
- <span class="comment">// unsafe ref of packed fields</span>
- <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="variable declaration reference">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration reference">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
- <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration reference">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
-
- <span class="comment">// unsafe auto ref of packed field</span>
- <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="method reference trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static mutable unsafe">MUT_GLOBAL</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
+ <span class="static mutable unsafe">MUT_GLOBAL</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="static mutable unsafe">MUT_GLOBAL</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static mutable">MUT_GLOBAL</span><span class="semicolon">;</span>
+ <span class="static unsafe">EXTERN_STATIC</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="static unsafe">EXTERN_STATIC</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="static">EXTERN_STATIC</span><span class="semicolon">;</span>
+
+ <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang unsafe">!</span><span class="parenthesis unsafe">(</span>
+ <span class="string_literal macro">"push {</span><span class="variable">base</span><span class="string_literal macro">}"</span><span class="comma macro">,</span>
+ <span class="variable declaration macro">base</span> <span class="operator macro">=</span> <span class="keyword const macro">const</span> <span class="numeric_literal macro">0</span>
+ <span class="parenthesis unsafe">)</span><span class="semicolon">;</span>
<span class="brace">}</span>
<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index e48ca86c46..504a1c970e 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -589,7 +589,7 @@ fn main() {
fn test_unsafe_highlighting() {
check_highlighting(
r#"
-//- minicore: sized
+//- minicore: sized, asm
macro_rules! id {
($($tt:tt)*) => {
$($tt)*
@@ -600,76 +600,80 @@ macro_rules! unsafe_deref {
*(&() as *const ())
};
}
-static mut MUT_GLOBAL: Struct = Struct { field: 0 };
-static GLOBAL: Struct = Struct { field: 0 };
-unsafe fn unsafe_fn() {}
union Union {
- a: u32,
- b: f32,
+ field: u32,
}
struct Struct { field: i32 }
+
+static mut MUT_GLOBAL: Struct = Struct { field: 0 };
+unsafe fn unsafe_fn() {}
+
impl Struct {
unsafe fn unsafe_method(&self) {}
}
-#[repr(packed)]
-struct Packed {
- a: u16,
-}
-
unsafe trait UnsafeTrait {}
-unsafe impl UnsafeTrait for Packed {}
+unsafe impl UnsafeTrait for Union {}
impl !UnsafeTrait for () {}
fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}
-trait DoTheAutoref {
- fn calls_autoref(&self);
-}
-
-impl DoTheAutoref for u16 {
- fn calls_autoref(&self) {}
+extern {
+ static EXTERN_STATIC: ();
}
fn main() {
- let x = &5 as *const _ as *const usize;
- let u = Union { b: 0 };
+ let x: *const usize;
+ let u: Union;
+ // id should be safe here, but unsafe_deref should not
id! {
unsafe { unsafe_deref!() }
};
unsafe {
+ // unsafe macro calls
unsafe_deref!();
id! { unsafe_deref!() };
// unsafe fn and method calls
unsafe_fn();
- let b = u.b;
- match u {
- Union { b: 0 } => (),
- Union { a } => (),
- }
+ self::unsafe_fn();
+ (unsafe_fn as unsafe fn())();
Struct { field: 0 }.unsafe_method();
+ u.field;
+ &u.field;
+ &raw const u.field;
+ // this should be safe!
+ let Union { field: _ };
+ // but not these
+ let Union { field };
+ let Union { field: true };
+ let Union { field: field };
+ let Union { field: ref field };
+ let Union { field: (ref field | 0) };
+
// unsafe deref
- *x;
+ *&raw const*&*x;
// unsafe access to a static mut
MUT_GLOBAL.field;
- GLOBAL.field;
+ &MUT_GLOBAL.field;
+ &raw const MUT_GLOBAL.field;
+ MUT_GLOBAL;
+ &MUT_GLOBAL;
+ &raw const MUT_GLOBAL;
+ EXTERN_STATIC;
+ &EXTERN_STATIC;
+ &raw const EXTERN_STATIC;
- // unsafe ref of packed fields
- let packed = Packed { a: 0 };
- let a = &packed.a;
- let ref a = packed.a;
- let Packed { ref a } = packed;
- let Packed { a: ref _a } = packed;
-
- // unsafe auto ref of packed field
- packed.a.calls_autoref();
+ core::arch::asm!(
+ "push {base}",
+ base$0 = const 0
+ );
}
}
"#,
diff --git a/docs/book/src/assists_generated.md b/docs/book/src/assists_generated.md
index 571113178d..918ae4a579 100644
--- a/docs/book/src/assists_generated.md
+++ b/docs/book/src/assists_generated.md
@@ -469,7 +469,7 @@ fn main() {
### `convert_closure_to_fn`
-**Source:** [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L27)
+**Source:** [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L25)
This converts a closure to a freestanding function, changing all captures to parameters.
@@ -1372,7 +1372,7 @@ fn main() {
### `flip_or_pattern`
**Source:** [flip_or_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/flip_or_pattern.rs#L9)
-Flips two trait bounds.
+Flips two patterns in an or-pattern.
#### Before
```rust
@@ -2302,7 +2302,7 @@ fn bar() {
### `inline_local_variable`
-**Source:** [inline_local_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_local_variable.rs#L21)
+**Source:** [inline_local_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_local_variable.rs#L17)
Inlines a local variable.