diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e40aeffbcd4f..4a06f3bcddb6 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -637,6 +637,10 @@ pub fn params(self, db: &dyn HirDatabase) -> Vec { db.function_data(self.id).params.clone() } + pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { + db.function_data(self.id).is_unsafe + } + pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { let _p = profile("Function::diagnostics"); let infer = db.infer(self.id.into()); @@ -1190,6 +1194,10 @@ pub fn is_fn(&self) -> bool { ) } + pub fn is_raw_ptr(&self) -> bool { + matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) + } + pub fn contains_unknown(&self) -> bool { return go(&self.ty.value); diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index e2130d931fdb..807195d25ad9 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs @@ -34,6 +34,7 @@ pub struct FunctionData { /// True if the first param is `self`. This is relevant to decide whether this /// can be called as a method. pub has_self_param: bool, + pub is_unsafe: bool, pub visibility: RawVisibility, } @@ -85,11 +86,14 @@ pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc +body { margin: 0; } +pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } + +.lifetime { color: #DFAF8F; font-style: italic; } +.comment { color: #7F9F7F; } +.struct, .enum { color: #7CB8BB; } +.enum_variant { color: #BDE0F3; } +.string_literal { color: #CC9393; } +.field { color: #94BFF3; } +.function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } +.parameter { color: #94BFF3; } +.text { color: #DCDCCC; } +.type { color: #7CB8BB; } +.builtin_type { color: #8CD0D3; } +.type_param { color: #DFAF8F; } +.attribute { color: #94BFF3; } +.numeric_literal { color: #BFEBBF; } +.bool_literal { color: #BFE6EB; } +.macro { color: #94BFF3; } +.module { color: #AFD8AF; } +.variable { color: #DCDCCC; } +.format_specifier { color: #CC696B; } +.mutable { text-decoration: underline; } + +.keyword { color: #F0DFAF; font-weight: bold; } +.keyword.unsafe { color: #BC8383; font-weight: bold; } +.control { font-style: italic; } + +
unsafe fn unsafe_fn() {}
+
+struct HasUnsafeFn;
+
+impl HasUnsafeFn {
+    unsafe fn unsafe_method(&self) {}
+}
+
+fn main() {
+    let x = &5 as *const usize;
+    unsafe {
+        unsafe_fn();
+        HasUnsafeFn.unsafe_method();
+        let y = *x;
+        let z = -x;
+    }
+}
\ No newline at end of file diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html index 352e350955fc..42c5f3e5515e 100644 --- a/crates/ra_ide/src/snapshots/highlighting.html +++ b/crates/ra_ide/src/snapshots/highlighting.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html index 2a0294f719f5..2dd61d20d691 100644 --- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html @@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 0b53ebe69563..19ecd54d6cf2 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs @@ -406,6 +406,23 @@ fn highlight_element( _ => h, } } + PREFIX_EXPR => { + let prefix_expr = element.into_node().and_then(ast::PrefixExpr::cast)?; + match prefix_expr.op_kind() { + Some(ast::PrefixOp::Deref) => {} + _ => return None, + } + + let expr = prefix_expr.expr()?; + let ty = sema.type_of_expr(&expr)?; + if !ty.is_raw_ptr() { + return None; + } + + let mut h = Highlight::new(HighlightTag::Operator); + h |= HighlightModifier::Unsafe; + h + } k if k.is_keyword() => { let h = Highlight::new(HighlightTag::Keyword); @@ -458,7 +475,13 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { Definition::Field(_) => HighlightTag::Field, Definition::ModuleDef(def) => match def { hir::ModuleDef::Module(_) => HighlightTag::Module, - hir::ModuleDef::Function(_) => HighlightTag::Function, + hir::ModuleDef::Function(func) => { + let mut h = HighlightTag::Function.into(); + if func.is_unsafe(db) { + h |= HighlightModifier::Unsafe; + } + return h; + } hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct, hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum, hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union, diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs index edfe61f39a13..7d946c98dae7 100644 --- a/crates/ra_ide/src/syntax_highlighting/html.rs +++ b/crates/ra_ide/src/syntax_highlighting/html.rs @@ -69,6 +69,7 @@ fn html_escape(text: &str) -> String { .string_literal { color: #CC9393; } .field { color: #94BFF3; } .function { color: #93E0E3; } +.operator.unsafe { color: #E28C14; } .parameter { color: #94BFF3; } .text { color: #DCDCCC; } .type { color: #7CB8BB; } diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs index 1514531de2e3..94f466966a3a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tags.rs +++ b/crates/ra_ide/src/syntax_highlighting/tags.rs @@ -24,12 +24,14 @@ pub enum HighlightTag { Enum, EnumVariant, Field, + FormatSpecifier, Function, Keyword, Lifetime, Macro, Module, NumericLiteral, + Operator, SelfKeyword, SelfType, Static, @@ -41,8 +43,6 @@ pub enum HighlightTag { Union, Local, UnresolvedReference, - FormatSpecifier, - Operator, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -72,12 +72,14 @@ fn as_str(self) -> &'static str { HighlightTag::Enum => "enum", HighlightTag::EnumVariant => "enum_variant", HighlightTag::Field => "field", + HighlightTag::FormatSpecifier => "format_specifier", HighlightTag::Function => "function", HighlightTag::Keyword => "keyword", HighlightTag::Lifetime => "lifetime", HighlightTag::Macro => "macro", HighlightTag::Module => "module", HighlightTag::NumericLiteral => "numeric_literal", + HighlightTag::Operator => "operator", HighlightTag::SelfKeyword => "self_keyword", HighlightTag::SelfType => "self_type", HighlightTag::Static => "static", @@ -89,8 +91,6 @@ fn as_str(self) -> &'static str { HighlightTag::Union => "union", HighlightTag::Local => "variable", HighlightTag::UnresolvedReference => "unresolved_reference", - HighlightTag::FormatSpecifier => "format_specifier", - HighlightTag::Operator => "operator", } } } diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 7dc229cab73d..36a1aa419bc3 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs @@ -258,3 +258,34 @@ fn main() { fs::write(dst_file, &actual_html).unwrap(); assert_eq_text!(expected_html, actual_html); } + +#[test] +fn test_unsafe_highlighting() { + let (analysis, file_id) = single_file( + r#" +unsafe fn unsafe_fn() {} + +struct HasUnsafeFn; + +impl HasUnsafeFn { + unsafe fn unsafe_method(&self) {} +} + +fn main() { + let x = &5 as *const usize; + unsafe { + unsafe_fn(); + HasUnsafeFn.unsafe_method(); + let y = *x; + let z = -x; + } +} +"# + .trim(), + ); + let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html"); + let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); + let expected_html = &read_text(&dst_file); + fs::write(dst_file, &actual_html).unwrap(); + assert_eq_text!(expected_html, actual_html); +}